diff --git a/0001-Backport-locale.getdefaultlocale-into-Salt.-It-s-get.patch b/0001-Backport-locale.getdefaultlocale-into-Salt.-It-s-get.patch new file mode 100644 index 0000000..11c30aa --- /dev/null +++ b/0001-Backport-locale.getdefaultlocale-into-Salt.-It-s-get.patch @@ -0,0 +1,516 @@ +From ad706711d3340bd84a62be83f84b43f5adb296e9 Mon Sep 17 00:00:00 2001 +From: Pedro Algarvio +Date: Wed, 22 Feb 2023 16:46:27 +0000 +Subject: [PATCH] Backport `locale.getdefaultlocale()` into Salt. It's getting + removed in Py 3.13 + +Signed-off-by: Pedro Algarvio +--- + salt/__init__.py | 43 +++++++++++++++-- + salt/grains/core.py | 108 +++++++++++++++++++----------------------- + salt/utils/locales.py | 39 ++++++++++++++- + 3 files changed, 125 insertions(+), 65 deletions(-) + +diff --git a/salt/__init__.py b/salt/__init__.py +index 485b17553c..32a73d568e 100644 +--- a/salt/__init__.py ++++ b/salt/__init__.py +@@ -39,6 +39,44 @@ warnings.filterwarnings( + ) + + ++def __getdefaultlocale(envvars=("LC_ALL", "LC_CTYPE", "LANG", "LANGUAGE")): ++ """ ++ This function was backported from Py3.11 which started triggering a ++ deprecation warning about it's removal in 3.13. ++ """ ++ import locale ++ ++ try: ++ # check if it's supported by the _locale module ++ import _locale ++ ++ code, encoding = _locale._getdefaultlocale() ++ except (ImportError, AttributeError): ++ pass ++ else: ++ # make sure the code/encoding values are valid ++ if sys.platform == "win32" and code and code[:2] == "0x": ++ # map windows language identifier to language name ++ code = locale.windows_locale.get(int(code, 0)) ++ # ...add other platform-specific processing here, if ++ # necessary... ++ return code, encoding ++ ++ # fall back on POSIX behaviour ++ import os ++ ++ lookup = os.environ.get ++ for variable in envvars: ++ localename = lookup(variable, None) ++ if localename: ++ if variable == "LANGUAGE": ++ localename = localename.split(":")[0] ++ break ++ else: ++ localename = "C" ++ return locale._parse_localename(localename) ++ ++ + def __define_global_system_encoding_variable__(): + import sys + +@@ -57,17 +95,14 @@ def __define_global_system_encoding_variable__(): + # If the system is properly configured this should return a valid + # encoding. MS Windows has problems with this and reports the wrong + # encoding +- import locale + + try: +- encoding = locale.getdefaultlocale()[-1] ++ encoding = __getdefaultlocale()[-1] + except ValueError: + # A bad locale setting was most likely found: + # https://github.com/saltstack/salt/issues/26063 + pass + +- # This is now garbage collectable +- del locale + if not encoding: + # This is most likely ascii which is not the best but we were + # unable to find a better encoding. If this fails, we fall all +diff --git a/salt/grains/core.py b/salt/grains/core.py +index 710c57f28f..afaa5389e3 100644 +--- a/salt/grains/core.py ++++ b/salt/grains/core.py +@@ -11,7 +11,6 @@ as those returned here + + import datetime + import hashlib +-import locale + import logging + import os + import platform +@@ -33,6 +32,7 @@ import salt.modules.smbios + import salt.utils.args + import salt.utils.dns + import salt.utils.files ++import salt.utils.locales + import salt.utils.network + import salt.utils.path + import salt.utils.pkg.rpm +@@ -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(): + 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(): + 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(): + + 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(): + 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) +@@ -1017,7 +1017,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: +@@ -1163,14 +1163,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" +@@ -1181,9 +1181,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: +@@ -1199,22 +1199,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": +@@ -1222,7 +1219,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" + +@@ -1251,7 +1248,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" + +@@ -1283,9 +1280,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"] +@@ -1441,7 +1436,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 +@@ -1632,7 +1627,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 +@@ -1871,18 +1866,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 +@@ -1900,7 +1890,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 +@@ -2624,7 +2614,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" +@@ -2698,7 +2688,7 @@ def locale_info(): + ( + grains["locale_info"]["defaultlanguage"], + grains["locale_info"]["defaultencoding"], +- ) = locale.getdefaultlocale() ++ ) = salt.utils.locales.getdefaultlocale() + except Exception: # pylint: disable=broad-except + # locale.getdefaultlocale can ValueError!! Catch anything else it + # might do, per #2205 +@@ -3165,7 +3155,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]) +@@ -3185,7 +3175,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") +@@ -3197,7 +3187,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": +@@ -3212,7 +3202,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": +@@ -3220,7 +3210,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"): +@@ -3234,7 +3224,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 = [ +@@ -3349,7 +3339,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+(.*)"), +@@ -3431,14 +3421,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/utils/locales.py b/salt/utils/locales.py +index 8017958d5d..a380ddbe7a 100644 +--- a/salt/utils/locales.py ++++ b/salt/utils/locales.py +@@ -1,8 +1,7 @@ + """ + the locale utils used by salt + """ +- +- ++import locale + import sys + + from salt.utils.decorators import memoize as real_memoize +@@ -83,3 +82,39 @@ def normalize_locale(loc): + comps["codeset"] = comps["codeset"].lower().replace("-", "") + comps["charmap"] = "" + return join_locale(comps) ++ ++ ++def getdefaultlocale(envvars=("LC_ALL", "LC_CTYPE", "LANG", "LANGUAGE")): ++ """ ++ This function was backported from Py3.11 which started triggering a ++ deprecation warning about it's removal in 3.13. ++ """ ++ try: ++ # check if it's supported by the _locale module ++ import _locale ++ ++ code, encoding = _locale._getdefaultlocale() ++ except (ImportError, AttributeError): ++ pass ++ else: ++ # make sure the code/encoding values are valid ++ if sys.platform == "win32" and code and code[:2] == "0x": ++ # map windows language identifier to language name ++ code = locale.windows_locale.get(int(code, 0)) ++ # ...add other platform-specific processing here, if ++ # necessary... ++ return code, encoding ++ ++ # fall back on POSIX behaviour ++ import os ++ ++ lookup = os.environ.get ++ for variable in envvars: ++ localename = lookup(variable, None) ++ if localename: ++ if variable == "LANGUAGE": ++ localename = localename.split(":")[0] ++ break ++ else: ++ localename = "C" ++ return locale._parse_localename(localename) +-- +2.39.2 + diff --git a/0002-Hide-known-DeprecationWarning-related-to-PEP-594.patch b/0002-Hide-known-DeprecationWarning-related-to-PEP-594.patch new file mode 100644 index 0000000..ae13ba5 --- /dev/null +++ b/0002-Hide-known-DeprecationWarning-related-to-PEP-594.patch @@ -0,0 +1,51 @@ +From 9a1efaa31d8b748c29d374c1726b940e43d5d36a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= + +Date: Thu, 22 Jun 2023 00:35:15 +0200 +Subject: [PATCH] Hide known DeprecationWarning related to PEP 594 + +The code is prepared to handle the situation where those modules will be +missing (with very minor functionality loss), so do not confuse the +users. +--- + salt/modules/linux_shadow.py | 6 +++++- + salt/utils/pycrypto.py | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/salt/modules/linux_shadow.py b/salt/modules/linux_shadow.py +index aa149ac4c8..6b0204b4b7 100644 +--- a/salt/modules/linux_shadow.py ++++ b/salt/modules/linux_shadow.py +@@ -18,7 +18,11 @@ import salt.utils.files + from salt.exceptions import CommandExecutionError + + try: +- import spwd ++ import warnings ++ ++ with warnings.catch_warnings(): ++ warnings.filterwarnings("ignore",category=DeprecationWarning) ++ import spwd + except ImportError: + pass + +diff --git a/salt/utils/pycrypto.py b/salt/utils/pycrypto.py +index a0f3874035..ab26ed75c3 100644 +--- a/salt/utils/pycrypto.py ++++ b/salt/utils/pycrypto.py +@@ -23,7 +23,11 @@ except ImportError: + HAS_RANDOM = False + + try: +- import crypt ++ import warnings ++ ++ with warnings.catch_warnings(): ++ warnings.filterwarnings("ignore",category=DeprecationWarning) ++ import crypt + + HAS_CRYPT = True + except (ImportError, PermissionError): +-- +2.39.2 + diff --git a/0003-Stop-using-the-deprecated-cgi-module.patch b/0003-Stop-using-the-deprecated-cgi-module.patch new file mode 100644 index 0000000..5bc683e --- /dev/null +++ b/0003-Stop-using-the-deprecated-cgi-module.patch @@ -0,0 +1,130 @@ +From 72fc1094cef37fd433d560bd094b611f38b7dd5b Mon Sep 17 00:00:00 2001 +From: Pedro Algarvio +Date: Wed, 22 Feb 2023 16:08:35 +0000 +Subject: [PATCH] Stop using the deprecated `cgi` module. + +Signed-off-by: Pedro Algarvio +--- + salt/utils/http.py | 48 ++++++++++++++++++++-------------------------- + 1 file changed, 21 insertions(+), 27 deletions(-) + +diff --git a/salt/utils/http.py b/salt/utils/http.py +index 9928847ed6..53a03377df 100644 +--- a/salt/utils/http.py ++++ b/salt/utils/http.py +@@ -5,7 +5,7 @@ and the like, but also useful for basic HTTP testing. + .. versionadded:: 2015.5.0 + """ + +-import cgi ++import email.message + import gzip + import http.client + import http.cookiejar +@@ -85,7 +85,7 @@ except ImportError: + HAS_CERTIFI = False + + log = logging.getLogger(__name__) +-USERAGENT = "Salt/{}".format(salt.version.__version__) ++USERAGENT = f"Salt/{salt.version.__version__}" + + + def __decompressContent(coding, pgctnt): +@@ -171,7 +171,7 @@ def query( + formdata_fieldname=None, + formdata_filename=None, + decode_body=True, +- **kwargs ++ **kwargs, + ): + """ + Query a resource, and decode the return data +@@ -296,7 +296,7 @@ def query( + auth = (username, password) + + if agent == USERAGENT: +- agent = "{} http.query()".format(agent) ++ agent = f"{agent} http.query()" + header_dict["User-agent"] = agent + + if backend == "requests": +@@ -361,14 +361,14 @@ def query( + url, + params=params, + files={formdata_fieldname: (formdata_filename, io.StringIO(data))}, +- **req_kwargs ++ **req_kwargs, + ) + else: + result = sess.request(method, url, params=params, data=data, **req_kwargs) + result.raise_for_status() + if stream is True: + # fake a HTTP response header +- header_callback("HTTP/1.0 {} MESSAGE".format(result.status_code)) ++ header_callback(f"HTTP/1.0 {result.status_code} MESSAGE") + # fake streaming the content + streaming_callback(result.content) + return { +@@ -484,15 +484,12 @@ def query( + result_headers = dict(result.info()) + result_text = result.read() + if "Content-Type" in result_headers: +- res_content_type, res_params = cgi.parse_header( +- result_headers["Content-Type"] +- ) +- if ( +- res_content_type.startswith("text/") +- and "charset" in res_params +- and not isinstance(result_text, str) +- ): +- result_text = result_text.decode(res_params["charset"]) ++ msg = email.message.EmailMessage() ++ msg.add_header("Content-Type", result_headers["Content-Type"]) ++ if msg.get_content_type().startswith("text/"): ++ content_charset = msg.get_content_charset() ++ if content_charset and not isinstance(result_text, str): ++ result_text = result_text.decode(content_charset) + if isinstance(result_text, bytes) and decode_body: + result_text = result_text.decode("utf-8") + ret["body"] = result_text +@@ -637,15 +634,12 @@ def query( + result_headers = result.headers + result_text = result.body + if "Content-Type" in result_headers: +- res_content_type, res_params = cgi.parse_header( +- result_headers["Content-Type"] +- ) +- if ( +- res_content_type.startswith("text/") +- and "charset" in res_params +- and not isinstance(result_text, str) +- ): +- result_text = result_text.decode(res_params["charset"]) ++ msg = email.message.EmailMessage() ++ msg.add_header("Content-Type", result_headers["Content-Type"]) ++ if msg.get_content_type().startswith("text/"): ++ content_charset = msg.get_content_charset() ++ if content_charset and not isinstance(result_text, str): ++ result_text = result_text.decode(content_charset) + if isinstance(result_text, bytes) and decode_body: + result_text = result_text.decode("utf-8") + ret["body"] = result_text +@@ -1039,12 +1033,12 @@ def _sanitize_url_components(comp_list, field): + """ + if not comp_list: + return "" +- elif comp_list[0].startswith("{}=".format(field)): +- ret = "{}=XXXXXXXXXX&".format(field) ++ elif comp_list[0].startswith(f"{field}="): ++ ret = f"{field}=XXXXXXXXXX&" + comp_list.remove(comp_list[0]) + return ret + _sanitize_url_components(comp_list, field) + else: +- ret = "{}&".format(comp_list[0]) ++ ret = f"{comp_list[0]}&" + comp_list.remove(comp_list[0]) + return ret + _sanitize_url_components(comp_list, field) + +-- +2.39.2 + diff --git a/0004-Fixed-committed-reviewer-suggestion.patch b/0004-Fixed-committed-reviewer-suggestion.patch new file mode 100644 index 0000000..4c2e5ce --- /dev/null +++ b/0004-Fixed-committed-reviewer-suggestion.patch @@ -0,0 +1,1530 @@ +From 7916ffb63e442542be8d8b1164994f98a541ff20 Mon Sep 17 00:00:00 2001 +From: David Murphy < dmurphy@saltstack.com> +Date: Wed, 7 Jun 2023 15:17:46 -0600 +Subject: [PATCH] Fixed committed reviewer suggestion + +--- + salt/modules/lxc.py | 276 ++++++++++----------- + salt/modules/network.py | 30 +-- + salt/modules/nspawn.py | 90 +++---- + salt/modules/vagrant.py | 36 ++- + tests/pytests/unit/modules/test_network.py | 2 +- + 5 files changed, 202 insertions(+), 232 deletions(-) + +diff --git a/salt/modules/lxc.py b/salt/modules/lxc.py +index 7db7855067..9d04963ba7 100644 +--- a/salt/modules/lxc.py ++++ b/salt/modules/lxc.py +@@ -119,7 +119,7 @@ def version(): + ver = Version(cversion["stdout"]) + if ver < Version("1.0"): + raise CommandExecutionError("LXC should be at least 1.0") +- __context__[k] = "{}".format(ver) ++ __context__[k] = f"{ver}" + return __context__.get(k, None) + + +@@ -141,7 +141,7 @@ def _ip_sort(ip): + idx = "201" + elif "::" in ip: + idx = "100" +- return "{}___{}".format(idx, ip) ++ return f"{idx}___{ip}" + + + def search_lxc_bridges(): +@@ -173,7 +173,7 @@ def search_lxc_bridges(): + for ifc, ip in __grains__.get("ip_interfaces", {}).items(): + if ifc in running_bridges: + bridges.add(ifc) +- elif os.path.exists("/sys/devices/virtual/net/{}/bridge".format(ifc)): ++ elif os.path.exists(f"/sys/devices/virtual/net/{ifc}/bridge"): + bridges.add(ifc) + bridges = list(bridges) + # if we found interfaces that have lxc in their names +@@ -186,7 +186,7 @@ def search_lxc_bridges(): + pref = "a" + elif "br0" == a: + pref = "c" +- return "{}_{}".format(pref, a) ++ return f"{pref}_{a}" + + bridges.sort(key=sort_bridges) + __context__["lxc.bridges"] = bridges +@@ -439,12 +439,12 @@ def cloud_init_interface(name, vm_=None, **kwargs): + if ip: + fullip = ip + if netmask: +- fullip += "/{}".format(netmask) ++ fullip += f"/{netmask}" + eth0["ipv4"] = fullip + if mac is not None: + eth0["mac"] = mac + for ix, iopts in enumerate(_cloud_get("additional_ips", [])): +- ifh = "eth{}".format(ix + 1) ++ ifh = f"eth{ix + 1}" + ethx = nic_opts.setdefault(ifh, {}) + if gw is None: + gw = iopts.get("gateway", ethx.get("gateway", None)) +@@ -465,7 +465,7 @@ def cloud_init_interface(name, vm_=None, **kwargs): + ethx["ipv4"] = aip + nm = iopts.get("netmask", "") + if nm: +- ethx["ipv4"] += "/{}".format(nm) ++ ethx["ipv4"] += f"/{nm}" + for i in ("mac", "hwaddr"): + if i in iopts: + ethx["mac"] = iopts[i] +@@ -543,7 +543,7 @@ def _get_profile(key, name, **kwargs): + profile_match = {} + else: + profile_match = __salt__["config.get"]( +- "lxc.{1}:{0}".format(name, key), default=None, merge="recurse" ++ f"lxc.{key}:{name}", default=None, merge="recurse" + ) + if profile_match is None: + # No matching profile, make the profile an empty dict so that +@@ -551,7 +551,7 @@ def _get_profile(key, name, **kwargs): + profile_match = {} + + if not isinstance(profile_match, dict): +- raise CommandExecutionError("lxc.{} must be a dictionary".format(key)) ++ raise CommandExecutionError(f"lxc.{key} must be a dictionary") + + # Overlay the kwargs to override matched profile data + overrides = salt.utils.args.clean_kwargs(**copy.deepcopy(kwargs)) +@@ -669,7 +669,7 @@ def _rand_cpu_str(cpu): + cpu = int(cpu) + avail = __salt__["status.nproc"]() + if cpu < avail: +- return "0-{}".format(avail) ++ return f"0-{avail}" + to_set = set() + while len(to_set) < cpu: + choice = random.randint(0, avail - 1) +@@ -832,7 +832,7 @@ def _network_conf(conf_tuples=None, **kwargs): + "ipv6", + ]: + continue +- ret.append({"lxc.network.{}".format(key): val}) ++ ret.append({f"lxc.network.{key}": val}) + # gateway (in automode) must be appended following network conf ! + if not gateway: + gateway = args.get("gateway", None) +@@ -892,7 +892,7 @@ def _get_lxc_default_data(**kwargs): + for k in ["utsname", "rootfs"]: + val = kwargs.get(k, None) + if val is not None: +- ret["lxc.{}".format(k)] = val ++ ret[f"lxc.{k}"] = val + autostart = kwargs.get("autostart") + # autostart can have made in kwargs, but with the None + # value which is invalid, we need an explicit boolean +@@ -1115,7 +1115,7 @@ def _get_base(**kwargs): + hash_ = salt.utils.hashutils.get_hash( + img_tar, __salt__["config.get"]("hash_type") + ) +- name = "__base_{}_{}_{}".format(proto, img_name, hash_) ++ name = f"__base_{proto}_{img_name}_{hash_}" + if not exists(name, path=path): + create( + name, template=template, image=image, path=path, vgname=vgname, **kwargs +@@ -1125,11 +1125,11 @@ def _get_base(**kwargs): + edit_conf( + info(name, path=path)["config"], + out_format="commented", +- **{"lxc.rootfs": rootfs} ++ **{"lxc.rootfs": rootfs}, + ) + return name + elif template: +- name = "__base_{}".format(template) ++ name = f"__base_{template}" + if not exists(name, path=path): + create( + name, template=template, image=image, path=path, vgname=vgname, **kwargs +@@ -1139,7 +1139,7 @@ def _get_base(**kwargs): + edit_conf( + info(name, path=path)["config"], + out_format="commented", +- **{"lxc.rootfs": rootfs} ++ **{"lxc.rootfs": rootfs}, + ) + return name + return "" +@@ -1171,7 +1171,7 @@ def init( + bootstrap_args=None, + bootstrap_shell=None, + bootstrap_url=None, +- **kwargs ++ **kwargs, + ): + """ + Initialize a new container. +@@ -1499,7 +1499,7 @@ def init( + try: + stop(name, path=path) + except (SaltInvocationError, CommandExecutionError) as exc: +- ret["comment"] = "Unable to stop container: {}".format(exc) ++ ret["comment"] = f"Unable to stop container: {exc}" + if changes: + ret["changes"] = changes_dict + return ret +@@ -1507,7 +1507,7 @@ def init( + try: + start(name, path=path) + except (SaltInvocationError, CommandExecutionError) as exc: +- ret["comment"] = "Unable to stop container: {}".format(exc) ++ ret["comment"] = f"Unable to stop container: {exc}" + if changes: + ret["changes"] = changes_dict + return ret +@@ -1515,7 +1515,7 @@ def init( + if remove_seed_marker: + run( + name, +- "rm -f '{}'".format(SEED_MARKER), ++ f"rm -f '{SEED_MARKER}'", + path=path, + chroot_fallback=False, + python_shell=False, +@@ -1524,11 +1524,11 @@ def init( + # set the default user/password, only the first time + if ret.get("result", True) and password: + gid = "/.lxc.initial_pass" +- gids = [gid, "/lxc.initial_pass", "/.lxc.{}.initial_pass".format(name)] ++ gids = [gid, "/lxc.initial_pass", f"/.lxc.{name}.initial_pass"] + if not any( + retcode( + name, +- 'test -e "{}"'.format(x), ++ f'test -e "{x}"', + chroot_fallback=True, + path=path, + ignore_retcode=True, +@@ -1544,7 +1544,7 @@ def init( + default_user not in users + and retcode( + name, +- "id {}".format(default_user), ++ f"id {default_user}", + python_shell=False, + path=path, + chroot_fallback=True, +@@ -1563,7 +1563,7 @@ def init( + encrypted=password_encrypted, + ) + except (SaltInvocationError, CommandExecutionError) as exc: +- msg = "{}: Failed to set password".format(user) + exc.strerror ++ msg = f"{user}: Failed to set password" + exc.strerror + # only hardfail in unrecoverable situation: + # root cannot be setted up + if user == "root": +@@ -1591,11 +1591,11 @@ def init( + if ret.get("result", True) and dnsservers: + # retro compatibility, test also old markers + gid = "/.lxc.initial_dns" +- gids = [gid, "/lxc.initial_dns", "/lxc.{}.initial_dns".format(name)] ++ gids = [gid, "/lxc.initial_dns", f"/lxc.{name}.initial_dns"] + if not any( + retcode( + name, +- 'test -e "{}"'.format(x), ++ f'test -e "{x}"', + chroot_fallback=True, + path=path, + ignore_retcode=True, +@@ -1628,13 +1628,13 @@ def init( + + # retro compatibility, test also old markers + if remove_seed_marker: +- run(name, "rm -f '{}'".format(SEED_MARKER), path=path, python_shell=False) ++ run(name, f"rm -f '{SEED_MARKER}'", path=path, python_shell=False) + gid = "/.lxc.initial_seed" + gids = [gid, "/lxc.initial_seed"] + if any( + retcode( + name, +- "test -e {}".format(x), ++ f"test -e {x}", + path=path, + chroot_fallback=True, + ignore_retcode=True, +@@ -1703,7 +1703,7 @@ def init( + try: + stop(name, path=path) + except (SaltInvocationError, CommandExecutionError) as exc: +- ret["comment"] = "Unable to stop container: {}".format(exc) ++ ret["comment"] = f"Unable to stop container: {exc}" + ret["result"] = False + + state_post = state(name, path=path) +@@ -1711,7 +1711,7 @@ def init( + changes.append({"state": {"old": state_pre, "new": state_post}}) + + if ret.get("result", True): +- ret["comment"] = "Container '{}' successfully initialized".format(name) ++ ret["comment"] = f"Container '{name}' successfully initialized" + ret["result"] = True + if changes: + ret["changes"] = changes_dict +@@ -1834,8 +1834,8 @@ def _after_ignition_network_profile(cmd, ret, name, network_profile, path, nic_o + # destroy the container if it was partially created + cmd = "lxc-destroy" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {}".format(name) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {name}" + __salt__["cmd.retcode"](cmd, python_shell=False) + raise CommandExecutionError( + "Container could not be created with cmd '{}': {}".format( +@@ -1943,7 +1943,7 @@ def create( + # Required params for 'download' template + download_template_deps = ("dist", "release", "arch") + +- cmd = "lxc-create -n {}".format(name) ++ cmd = f"lxc-create -n {name}" + + profile = get_container_profile(copy.deepcopy(profile)) + kw_overrides = copy.deepcopy(kwargs) +@@ -1959,7 +1959,7 @@ def create( + + path = select("path") + if exists(name, path=path): +- raise CommandExecutionError("Container '{}' already exists".format(name)) ++ raise CommandExecutionError(f"Container '{name}' already exists") + + tvg = select("vgname") + vgname = tvg if tvg else __salt__["config.get"]("lxc.vgname") +@@ -1997,31 +1997,31 @@ def create( + ) + options["imgtar"] = img_tar + if path: +- cmd += " -P {}".format(pipes.quote(path)) ++ cmd += f" -P {pipes.quote(path)}" + if not os.path.exists(path): + os.makedirs(path) + if config: +- cmd += " -f {}".format(config) ++ cmd += f" -f {config}" + if template: +- cmd += " -t {}".format(template) ++ cmd += f" -t {template}" + if backing: + backing = backing.lower() +- cmd += " -B {}".format(backing) ++ cmd += f" -B {backing}" + if backing in ("zfs",): + if zfsroot: +- cmd += " --zfsroot {}".format(zfsroot) ++ cmd += f" --zfsroot {zfsroot}" + if backing in ("lvm",): + if lvname: +- cmd += " --lvname {}".format(lvname) ++ cmd += f" --lvname {lvname}" + if vgname: +- cmd += " --vgname {}".format(vgname) ++ cmd += f" --vgname {vgname}" + if thinpool: +- cmd += " --thinpool {}".format(thinpool) ++ cmd += f" --thinpool {thinpool}" + if backing not in ("dir", "overlayfs"): + if fstype: +- cmd += " --fstype {}".format(fstype) ++ cmd += f" --fstype {fstype}" + if size: +- cmd += " --fssize {}".format(size) ++ cmd += f" --fssize {size}" + + if options: + if template == "download": +@@ -2034,7 +2034,7 @@ def create( + ) + cmd += " --" + for key, val in options.items(): +- cmd += " --{} {}".format(key, val) ++ cmd += f" --{key} {val}" + + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + # please do not merge extra conflicting stuff +@@ -2108,13 +2108,11 @@ def clone(name, orig, profile=None, network_profile=None, nic_opts=None, **kwarg + + path = select("path") + if exists(name, path=path): +- raise CommandExecutionError("Container '{}' already exists".format(name)) ++ raise CommandExecutionError(f"Container '{name}' already exists") + + _ensure_exists(orig, path=path) + if state(orig, path=path) != "stopped": +- raise CommandExecutionError( +- "Container '{}' must be stopped to be cloned".format(orig) +- ) ++ raise CommandExecutionError(f"Container '{orig}' must be stopped to be cloned") + + backing = select("backing") + snapshot = select("snapshot") +@@ -2132,21 +2130,21 @@ def clone(name, orig, profile=None, network_profile=None, nic_opts=None, **kwarg + if Version(version()) >= Version("2.0"): + # https://linuxcontainers.org/lxc/manpages//man1/lxc-copy.1.html + cmd = "lxc-copy" +- cmd += " {} -n {} -N {}".format(snapshot, orig, name) ++ cmd += f" {snapshot} -n {orig} -N {name}" + else: + # https://linuxcontainers.org/lxc/manpages//man1/lxc-clone.1.html + cmd = "lxc-clone" +- cmd += " {} -o {} -n {}".format(snapshot, orig, name) ++ cmd += f" {snapshot} -o {orig} -n {name}" + if path: +- cmd += " -P {}".format(pipes.quote(path)) ++ cmd += f" -P {pipes.quote(path)}" + if not os.path.exists(path): + os.makedirs(path) + if backing: + backing = backing.lower() +- cmd += " -B {}".format(backing) ++ cmd += f" -B {backing}" + if backing not in ("dir", "overlayfs"): + if size: +- cmd += " -L {}".format(size) ++ cmd += f" -L {size}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + # please do not merge extra conflicting stuff + # inside those two line (ret =, return) +@@ -2177,7 +2175,7 @@ def ls_(active=None, cache=True, path=None): + salt '*' lxc.ls + salt '*' lxc.ls active=True + """ +- contextvar = "lxc.ls{}".format(path) ++ contextvar = f"lxc.ls{path}" + if active: + contextvar += ".active" + if cache and (contextvar in __context__): +@@ -2186,7 +2184,7 @@ def ls_(active=None, cache=True, path=None): + ret = [] + cmd = "lxc-ls" + if path: +- cmd += " -P {}".format(pipes.quote(path)) ++ cmd += f" -P {pipes.quote(path)}" + if active: + cmd += " --active" + output = __salt__["cmd.run_stdout"](cmd, python_shell=False) +@@ -2242,8 +2240,8 @@ def list_(extra=False, limit=None, path=None): + for container in ctnrs: + cmd = "lxc-info" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {}".format(container) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {container}" + c_info = __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="debug") + c_state = None + for line in c_info.splitlines(): +@@ -2294,20 +2292,20 @@ def _change_state( + return { + "result": True, + "state": {"old": expected, "new": expected}, +- "comment": "Container '{}' already {}".format(name, expected), ++ "comment": f"Container '{name}' already {expected}", + } + + if cmd == "lxc-destroy": + # Kill the container first + scmd = "lxc-stop" + if path: +- scmd += " -P {}".format(pipes.quote(path)) +- scmd += " -k -n {}".format(name) ++ scmd += f" -P {pipes.quote(path)}" ++ scmd += f" -k -n {name}" + __salt__["cmd.run"](scmd, python_shell=False) + + if path and " -P " not in cmd: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {}".format(name) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {name}" + + # certain lxc commands need to be taken with care (lxc-start) + # as te command itself mess with double forks; we must not +@@ -2337,8 +2335,8 @@ def _change_state( + # some commands do not wait, so we will + rcmd = "lxc-wait" + if path: +- rcmd += " -P {}".format(pipes.quote(path)) +- rcmd += " -n {} -s {}".format(name, expected.upper()) ++ rcmd += f" -P {pipes.quote(path)}" ++ rcmd += f" -n {name} -s {expected.upper()}" + __salt__["cmd.run"](rcmd, python_shell=False, timeout=30) + _clear_context() + post = state(name, path=path) +@@ -2351,7 +2349,7 @@ def _ensure_exists(name, path=None): + Raise an exception if the container does not exist + """ + if not exists(name, path=path): +- raise CommandExecutionError("Container '{}' does not exist".format(name)) ++ raise CommandExecutionError(f"Container '{name}' does not exist") + + + def _ensure_running(name, no_start=False, path=None): +@@ -2373,11 +2371,11 @@ def _ensure_running(name, no_start=False, path=None): + return start(name, path=path) + elif pre == "stopped": + if no_start: +- raise CommandExecutionError("Container '{}' is not running".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is not running") + return start(name, path=path) + elif pre == "frozen": + if no_start: +- raise CommandExecutionError("Container '{}' is not running".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is not running") + return unfreeze(name, path=path) + + +@@ -2459,13 +2457,11 @@ def start(name, **kwargs): + lxc_config = os.path.join(cpath, name, "config") + # we try to start, even without config, if global opts are there + if os.path.exists(lxc_config): +- cmd += " -f {}".format(pipes.quote(lxc_config)) ++ cmd += f" -f {pipes.quote(lxc_config)}" + cmd += " -d" + _ensure_exists(name, path=path) + if state(name, path=path) == "frozen": +- raise CommandExecutionError( +- "Container '{}' is frozen, use lxc.unfreeze".format(name) +- ) ++ raise CommandExecutionError(f"Container '{name}' is frozen, use lxc.unfreeze") + # lxc-start daemonize itself violently, we must not communicate with it + use_vt = kwargs.get("use_vt", None) + with_communicate = kwargs.get("with_communicate", False) +@@ -2560,11 +2556,11 @@ def freeze(name, **kwargs): + start_ = kwargs.get("start", False) + if orig_state == "stopped": + if not start_: +- raise CommandExecutionError("Container '{}' is stopped".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is stopped") + start(name, path=path) + cmd = "lxc-freeze" + if path: +- cmd += " -P {}".format(pipes.quote(path)) ++ cmd += f" -P {pipes.quote(path)}" + ret = _change_state(cmd, name, "frozen", use_vt=use_vt, path=path) + if orig_state == "stopped" and start_: + ret["state"]["old"] = orig_state +@@ -2596,10 +2592,10 @@ def unfreeze(name, path=None, use_vt=None): + """ + _ensure_exists(name, path=path) + if state(name, path=path) == "stopped": +- raise CommandExecutionError("Container '{}' is stopped".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is stopped") + cmd = "lxc-unfreeze" + if path: +- cmd += " -P {}".format(pipes.quote(path)) ++ cmd += f" -P {pipes.quote(path)}" + return _change_state(cmd, name, "running", path=path, use_vt=use_vt) + + +@@ -2635,7 +2631,7 @@ def destroy(name, stop=False, path=None): + """ + _ensure_exists(name, path=path) + if not stop and state(name, path=path) != "stopped": +- raise CommandExecutionError("Container '{}' is not stopped".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is not stopped") + return _change_state("lxc-destroy", name, None, path=path) + + +@@ -2684,7 +2680,7 @@ def state(name, path=None): + """ + # Don't use _ensure_exists() here, it will mess with _change_state() + +- cachekey = "lxc.state.{}{}".format(name, path) ++ cachekey = f"lxc.state.{name}{path}" + try: + return __context__[cachekey] + except KeyError: +@@ -2693,13 +2689,13 @@ def state(name, path=None): + else: + cmd = "lxc-info" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {}".format(name) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {name}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: + _clear_context() + raise CommandExecutionError( +- "Unable to get state of container '{}'".format(name) ++ f"Unable to get state of container '{name}'" + ) + c_infos = ret["stdout"].splitlines() + c_state = None +@@ -2731,13 +2727,11 @@ def get_parameter(name, parameter, path=None): + _ensure_exists(name, path=path) + cmd = "lxc-cgroup" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {} {}".format(name, parameter) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {name} {parameter}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: +- raise CommandExecutionError( +- "Unable to retrieve value for '{}'".format(parameter) +- ) ++ raise CommandExecutionError(f"Unable to retrieve value for '{parameter}'") + return ret["stdout"].strip() + + +@@ -2762,8 +2756,8 @@ def set_parameter(name, parameter, value, path=None): + + cmd = "lxc-cgroup" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " -n {} {} {}".format(name, parameter, value) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -n {name} {parameter} {value}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: + return False +@@ -2787,7 +2781,7 @@ def info(name, path=None): + + salt '*' lxc.info name + """ +- cachekey = "lxc.info.{}{}".format(name, path) ++ cachekey = f"lxc.info.{name}{path}" + try: + return __context__[cachekey] + except KeyError: +@@ -2799,9 +2793,7 @@ def info(name, path=None): + conf_file = os.path.join(cpath, str(name), "config") + + if not os.path.isfile(conf_file): +- raise CommandExecutionError( +- "LXC config file {} does not exist".format(conf_file) +- ) ++ raise CommandExecutionError(f"LXC config file {conf_file} does not exist") + + ret = {} + config = [] +@@ -3000,9 +2992,7 @@ def update_lxc_conf(name, lxc_conf, lxc_conf_unset, path=None): + cpath = get_root_path(path) + lxc_conf_p = os.path.join(cpath, name, "config") + if not os.path.exists(lxc_conf_p): +- raise SaltInvocationError( +- "Configuration file {} does not exist".format(lxc_conf_p) +- ) ++ raise SaltInvocationError(f"Configuration file {lxc_conf_p} does not exist") + + changes = {"edited": [], "added": [], "removed": []} + ret = {"changes": changes, "result": True, "comment": ""} +@@ -3054,17 +3044,15 @@ def update_lxc_conf(name, lxc_conf, lxc_conf_unset, path=None): + conf = "" + for key, val in dest_lxc_conf: + if not val: +- conf += "{}\n".format(key) ++ conf += f"{key}\n" + else: +- conf += "{} = {}\n".format(key.strip(), val.strip()) ++ conf += f"{key.strip()} = {val.strip()}\n" + conf_changed = conf != orig_config + chrono = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if conf_changed: + # DO NOT USE salt.utils.files.fopen here, i got (kiorky) + # problems with lxc configs which were wiped ! +- with salt.utils.files.fopen( +- "{}.{}".format(lxc_conf_p, chrono), "w" +- ) as wfic: ++ with salt.utils.files.fopen(f"{lxc_conf_p}.{chrono}", "w") as wfic: + wfic.write(salt.utils.stringutils.to_str(conf)) + with salt.utils.files.fopen(lxc_conf_p, "w") as wfic: + wfic.write(salt.utils.stringutils.to_str(conf)) +@@ -3113,8 +3101,8 @@ def set_dns(name, dnsservers=None, searchdomains=None, path=None): + searchdomains = searchdomains.split(",") + except AttributeError: + raise SaltInvocationError("Invalid input for 'searchdomains' parameter") +- dns = ["nameserver {}".format(x) for x in dnsservers] +- dns.extend(["search {}".format(x) for x in searchdomains]) ++ dns = [f"nameserver {x}" for x in dnsservers] ++ dns.extend([f"search {x}" for x in searchdomains]) + dns = "\n".join(dns) + "\n" + # we may be using resolvconf in the container + # We need to handle that case with care: +@@ -3129,7 +3117,7 @@ def set_dns(name, dnsservers=None, searchdomains=None, path=None): + # - We finally also set /etc/resolv.conf in all cases + rstr = __salt__["test.random_hash"]() + # no tmp here, apparmor won't let us execute ! +- script = "/sbin/{}_dns.sh".format(rstr) ++ script = f"/sbin/{rstr}_dns.sh" + DNS_SCRIPT = "\n".join( + [ + # 'set -x', +@@ -3153,7 +3141,7 @@ def set_dns(name, dnsservers=None, searchdomains=None, path=None): + ] + ) + result = run_all( +- name, "tee {}".format(script), path=path, stdin=DNS_SCRIPT, python_shell=True ++ name, f"tee {script}", path=path, stdin=DNS_SCRIPT, python_shell=True + ) + if result["retcode"] == 0: + result = run_all( +@@ -3170,7 +3158,7 @@ def set_dns(name, dnsservers=None, searchdomains=None, path=None): + python_shell=True, + ) + if result["retcode"] != 0: +- error = "Unable to write to /etc/resolv.conf in container '{}'".format(name) ++ error = f"Unable to write to /etc/resolv.conf in container '{name}'" + if result["stderr"]: + error += ": {}".format(result["stderr"]) + raise CommandExecutionError(error) +@@ -3193,12 +3181,12 @@ def running_systemd(name, cache=True, path=None): + salt '*' lxc.running_systemd ubuntu + + """ +- k = "lxc.systemd.test.{}{}".format(name, path) ++ k = f"lxc.systemd.test.{name}{path}" + ret = __context__.get(k, None) + if ret is None or not cache: + rstr = __salt__["test.random_hash"]() + # no tmp here, apparmor won't let us execute ! +- script = "/sbin/{}_testsystemd.sh".format(rstr) ++ script = f"/sbin/{rstr}_testsystemd.sh" + # ubuntu already had since trusty some bits of systemd but was + # still using upstart ... + # we need to be a bit more careful that just testing that systemd +@@ -3227,7 +3215,7 @@ def running_systemd(name, cache=True, path=None): + """ + ) + result = run_all( +- name, "tee {}".format(script), path=path, stdin=_script, python_shell=True ++ name, f"tee {script}", path=path, stdin=_script, python_shell=True + ) + if result["retcode"] == 0: + result = run_all( +@@ -3237,9 +3225,7 @@ def running_systemd(name, cache=True, path=None): + python_shell=True, + ) + else: +- raise CommandExecutionError( +- "lxc {} failed to copy initd tester".format(name) +- ) ++ raise CommandExecutionError(f"lxc {name} failed to copy initd tester") + run_all( + name, + 'sh -c \'if [ -f "{0}" ];then rm -f "{0}";fi\''.format(script), +@@ -3361,9 +3347,9 @@ def wait_started(name, path=None, timeout=300): + + """ + if not exists(name, path=path): +- raise CommandExecutionError("Container {} does does exists".format(name)) ++ raise CommandExecutionError(f"Container {name} does does exists") + if not state(name, path=path) == "running": +- raise CommandExecutionError("Container {} is not running".format(name)) ++ raise CommandExecutionError(f"Container {name} is not running") + ret = False + if running_systemd(name, path=path): + test_started = test_sd_started_state +@@ -3520,7 +3506,7 @@ def bootstrap( + seeded = ( + retcode( + name, +- "test -e '{}'".format(SEED_MARKER), ++ f"test -e '{SEED_MARKER}'", + path=path, + chroot_fallback=True, + ignore_retcode=True, +@@ -3543,9 +3529,9 @@ def bootstrap( + if needs_install or force_install or unconditional_install: + if install: + rstr = __salt__["test.random_hash"]() +- configdir = "/var/tmp/.c_{}".format(rstr) ++ configdir = f"/var/tmp/.c_{rstr}" + +- cmd = "install -m 0700 -d {}".format(configdir) ++ cmd = f"install -m 0700 -d {configdir}" + if run_all(name, cmd, path=path, python_shell=False)["retcode"] != 0: + log.error("tmpdir %s creation failed %s", configdir, cmd) + return False +@@ -3553,11 +3539,11 @@ def bootstrap( + bs_ = __salt__["config.gather_bootstrap_script"]( + bootstrap=bootstrap_url + ) +- script = "/sbin/{}_bootstrap.sh".format(rstr) ++ script = f"/sbin/{rstr}_bootstrap.sh" + copy_to(name, bs_, script, path=path) + result = run_all( + name, +- 'sh -c "chmod +x {}"'.format(script), ++ f'sh -c "chmod +x {script}"', + path=path, + python_shell=True, + ) +@@ -3631,7 +3617,7 @@ def bootstrap( + freeze(name, path=path) + # mark seeded upon successful install + if ret: +- run(name, "touch '{}'".format(SEED_MARKER), path=path, python_shell=False) ++ run(name, f"touch '{SEED_MARKER}'", path=path, python_shell=False) + return ret + + +@@ -3652,7 +3638,7 @@ def attachable(name, path=None): + + salt 'minion' lxc.attachable ubuntu + """ +- cachekey = "lxc.attachable{}{}".format(name, path) ++ cachekey = f"lxc.attachable{name}{path}" + try: + return __context__[cachekey] + except KeyError: +@@ -3662,8 +3648,8 @@ def attachable(name, path=None): + log.debug("Checking if LXC container %s is attachable", name) + cmd = "lxc-attach" + if path: +- cmd += " -P {}".format(pipes.quote(path)) +- cmd += " --clear-env -n {} -- /usr/bin/env".format(name) ++ cmd += f" -P {pipes.quote(path)}" ++ cmd += f" --clear-env -n {name} -- /usr/bin/env" + result = ( + __salt__["cmd.retcode"]( + cmd, python_shell=False, output_loglevel="quiet", ignore_retcode=True +@@ -3719,7 +3705,7 @@ def _run( + ) + else: + if not chroot_fallback: +- raise CommandExecutionError("{} is not attachable.".format(name)) ++ raise CommandExecutionError(f"{name} is not attachable.") + rootfs = info(name, path=path).get("rootfs") + # Set context var to make cmd.run_chroot run cmd.run instead of + # cmd.run_all. +@@ -4214,7 +4200,7 @@ def _get_md5(name, path): + Get the MD5 checksum of a file from a container + """ + output = run_stdout( +- name, 'md5sum "{}"'.format(path), chroot_fallback=True, ignore_retcode=True ++ name, f'md5sum "{path}"', chroot_fallback=True, ignore_retcode=True + ) + try: + return output.split()[0] +@@ -4381,7 +4367,7 @@ def write_conf(conf_file, conf): + line[key], + (str, (str,), (int,), float), + ): +- out_line = " = ".join((key, "{}".format(line[key]))) ++ out_line = " = ".join((key, f"{line[key]}")) + elif isinstance(line[key], dict): + out_line = " = ".join((key, line[key]["value"])) + if "comment" in line[key]: +@@ -4474,7 +4460,7 @@ def edit_conf( + net_changes = _config_list( + conf, + only_net=True, +- **{"network_profile": DEFAULT_NIC, "nic_opts": nic_opts} ++ **{"network_profile": DEFAULT_NIC, "nic_opts": nic_opts}, + ) + if net_changes: + lxc_config.extend(net_changes) +@@ -4524,20 +4510,20 @@ def reboot(name, path=None): + salt 'minion' lxc.reboot myvm + + """ +- ret = {"result": True, "changes": {}, "comment": "{} rebooted".format(name)} ++ ret = {"result": True, "changes": {}, "comment": f"{name} rebooted"} + does_exist = exists(name, path=path) + if does_exist and (state(name, path=path) == "running"): + try: + stop(name, path=path) + except (SaltInvocationError, CommandExecutionError) as exc: +- ret["comment"] = "Unable to stop container: {}".format(exc) ++ ret["comment"] = f"Unable to stop container: {exc}" + ret["result"] = False + return ret + if does_exist and (state(name, path=path) != "running"): + try: + start(name, path=path) + except (SaltInvocationError, CommandExecutionError) as exc: +- ret["comment"] = "Unable to stop container: {}".format(exc) ++ ret["comment"] = f"Unable to stop container: {exc}" + ret["result"] = False + return ret + ret["changes"][name] = "rebooted" +@@ -4559,7 +4545,7 @@ def reconfigure( + utsname=None, + rootfs=None, + path=None, +- **kwargs ++ **kwargs, + ): + """ + Reconfigure a container. +@@ -4625,7 +4611,7 @@ def reconfigure( + path = os.path.join(cpath, name, "config") + ret = { + "name": name, +- "comment": "config for {} up to date".format(name), ++ "comment": f"config for {name} up to date", + "result": True, + "changes": changes, + } +@@ -4677,7 +4663,7 @@ def reconfigure( + edit_conf(path, out_format="commented", lxc_config=new_cfg) + chunks = read_conf(path, out_format="commented") + if old_chunks != chunks: +- ret["comment"] = "{} lxc config updated".format(name) ++ ret["comment"] = f"{name} lxc config updated" + if state(name, path=path) == "running": + cret = reboot(name, path=path) + ret["result"] = cret["result"] +@@ -4763,9 +4749,9 @@ def get_pid(name, path=None): + """ + if name not in list_(limit="running", path=path): + raise CommandExecutionError( +- "Container {} is not running, can't determine PID".format(name) ++ f"Container {name} is not running, can't determine PID" + ) +- info = __salt__["cmd.run"]("lxc-info -n {}".format(name)).split("\n") ++ info = __salt__["cmd.run"](f"lxc-info -n {name}").split("\n") + pid = [ + line.split(":")[1].strip() + for line in info +@@ -4812,21 +4798,19 @@ def add_veth(name, interface_name, bridge=None, path=None): + raise CommandExecutionError( + "Directory /var/run required for lxc.add_veth doesn't exists" + ) +- if not __salt__["file.file_exists"]("/proc/{}/ns/net".format(pid)): ++ if not __salt__["file.file_exists"](f"/proc/{pid}/ns/net"): + raise CommandExecutionError( +- "Proc file for container {} network namespace doesn't exists".format(name) ++ f"Proc file for container {name} network namespace doesn't exists" + ) + + if not __salt__["file.directory_exists"]("/var/run/netns"): + __salt__["file.mkdir"]("/var/run/netns") + + # Ensure that the symlink is up to date (change on container restart) +- if __salt__["file.is_link"]("/var/run/netns/{}".format(name)): +- __salt__["file.remove"]("/var/run/netns/{}".format(name)) ++ if __salt__["file.is_link"](f"/var/run/netns/{name}"): ++ __salt__["file.remove"](f"/var/run/netns/{name}") + +- __salt__["file.symlink"]( +- "/proc/{}/ns/net".format(pid), "/var/run/netns/{}".format(name) +- ) ++ __salt__["file.symlink"](f"/proc/{pid}/ns/net", f"/var/run/netns/{name}") + + # Ensure that interface doesn't exists + interface_exists = 0 == __salt__["cmd.retcode"]( +@@ -4851,12 +4835,10 @@ def add_veth(name, interface_name, bridge=None, path=None): + ) + != 0 + ): ++ raise CommandExecutionError(f"Error while creating the veth pair {random_veth}") ++ if __salt__["cmd.retcode"](f"ip link set dev {random_veth} up") != 0: + raise CommandExecutionError( +- "Error while creating the veth pair {}".format(random_veth) +- ) +- if __salt__["cmd.retcode"]("ip link set dev {} up".format(random_veth)) != 0: +- raise CommandExecutionError( +- "Error while bringing up host-side veth {}".format(random_veth) ++ f"Error while bringing up host-side veth {random_veth}" + ) + + # Attach it to the container +@@ -4872,7 +4854,7 @@ def add_veth(name, interface_name, bridge=None, path=None): + ) + ) + +- __salt__["file.remove"]("/var/run/netns/{}".format(name)) ++ __salt__["file.remove"](f"/var/run/netns/{name}") + + if bridge is not None: + __salt__["bridge.addif"](bridge, random_veth) +diff --git a/salt/modules/network.py b/salt/modules/network.py +index 473ce7a7cf..de40795676 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 = {} + +@@ -1454,7 +1454,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(): +@@ -1486,7 +1486,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])) + +@@ -1544,7 +1544,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_: +@@ -1720,7 +1720,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-" +@@ -1824,7 +1824,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"): +@@ -1868,7 +1868,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) + +@@ -1926,7 +1926,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\.:]+)" +@@ -1950,7 +1950,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} +@@ -1979,7 +1979,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} +@@ -2007,7 +2007,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/nspawn.py b/salt/modules/nspawn.py +index b0aaca413e..3c8e8c0f76 100644 +--- a/salt/modules/nspawn.py ++++ b/salt/modules/nspawn.py +@@ -81,7 +81,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 +@@ -115,14 +115,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}" + ) + + +@@ -132,10 +132,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): +@@ -147,7 +145,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) +@@ -183,7 +181,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) +@@ -224,7 +222,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) +@@ -258,7 +256,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() +@@ -280,7 +278,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, +@@ -350,9 +348,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( +@@ -706,9 +702,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): +@@ -786,7 +782,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 +@@ -803,20 +799,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") +@@ -849,7 +845,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 + + +@@ -933,7 +929,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() +@@ -952,7 +948,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" +@@ -992,11 +988,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", +@@ -1052,7 +1046,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 +@@ -1070,7 +1064,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 +@@ -1089,9 +1083,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: +@@ -1112,9 +1106,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: +@@ -1204,7 +1198,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) +@@ -1214,7 +1208,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: +@@ -1222,7 +1216,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: +@@ -1257,15 +1251,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"]) +@@ -1315,10 +1307,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 +@@ -1346,13 +1338,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 = { +@@ -1384,7 +1376,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/vagrant.py b/salt/modules/vagrant.py +index 0df88afde2..497cddccb7 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 + + +@@ -691,6 +687,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 +-- +2.39.2 + diff --git a/0005-Stop-using-the-deprecated-pipes-module.patch b/0005-Stop-using-the-deprecated-pipes-module.patch new file mode 100644 index 0000000..1ba9c5d --- /dev/null +++ b/0005-Stop-using-the-deprecated-pipes-module.patch @@ -0,0 +1,2839 @@ +From e814134020c89d91d593b9904526fb19aadb8a2d Mon Sep 17 00:00:00 2001 +From: Pedro Algarvio +Date: Wed, 22 Feb 2023 16:12:16 +0000 +Subject: [PATCH] Stop using the deprecated `pipes` module + +Signed-off-by: Pedro Algarvio +--- + salt/modules/container_resource.py | 74 +++----- + salt/modules/deb_postgres.py | 16 +- + salt/modules/dockermod.py | 178 ++++++++---------- + salt/modules/lxc.py | 32 ++-- + salt/modules/mac_keychain.py | 32 +--- + salt/modules/macpackage.py | 45 ++--- + salt/modules/openstack_config.py | 41 ++-- + salt/modules/postgres.py | 116 ++++++------ + salt/utils/cloud.py | 289 +++++++++++++---------------- + salt/utils/jinja.py | 25 ++- + 10 files changed, 353 insertions(+), 495 deletions(-) + +diff --git a/salt/modules/container_resource.py b/salt/modules/container_resource.py +index a29cba2e46..ceec72a7b2 100644 +--- a/salt/modules/container_resource.py ++++ b/salt/modules/container_resource.py +@@ -8,13 +8,11 @@ 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 + import os +-import pipes ++import shlex + import time + import traceback + +@@ -68,14 +66,14 @@ def _nsenter(pid): + """ + Return the nsenter command to attach to the named container + """ +- return "nsenter --target {} --mount --uts --ipc --net --pid".format(pid) ++ return f"nsenter --target {pid} --mount --uts --ipc --net --pid" + + + def _get_md5(name, path, run_func): + """ + Get the MD5 checksum of a file from a container + """ +- output = run_func(name, "md5sum {}".format(pipes.quote(path)), ignore_retcode=True)[ ++ output = run_func(name, f"md5sum {shlex.quote(path)}", ignore_retcode=True)[ + "stdout" + ] + try: +@@ -102,10 +100,10 @@ def cache_file(source): + 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}") + return cached_source + except AttributeError: +- raise SaltInvocationError("Invalid source file {}".format(source)) ++ raise SaltInvocationError(f"Invalid source file {source}") + return source + + +@@ -164,55 +162,47 @@ def run( + if exec_driver == "lxc-attach": + full_cmd = "lxc-attach " + if path: +- full_cmd += "-P {} ".format(pipes.quote(path)) ++ full_cmd += f"-P {shlex.quote(path)} " + if keep_env is not True: + full_cmd += "--clear-env " + if "PATH" not in to_keep: +- full_cmd += "--set-var {} ".format(PATH) ++ full_cmd += f"--set-var {PATH} " + # --clear-env results in a very restrictive PATH + # (/bin:/usr/bin), use a good fallback. + full_cmd += " ".join( + [ +- "--set-var {}={}".format(x, pipes.quote(os.environ[x])) ++ f"--set-var {x}={shlex.quote(os.environ[x])}" + for x in to_keep + if x in os.environ + ] + ) +- full_cmd += " -n {} -- {}".format(pipes.quote(name), cmd) ++ full_cmd += f" -n {shlex.quote(name)} -- {cmd}" + elif exec_driver == "nsenter": +- pid = __salt__["{}.pid".format(container_type)](name) +- full_cmd = "nsenter --target {} --mount --uts --ipc --net --pid -- ".format(pid) ++ pid = __salt__[f"{container_type}.pid"](name) ++ full_cmd = f"nsenter --target {pid} --mount --uts --ipc --net --pid -- " + if keep_env is not True: + full_cmd += "env -i " + if "PATH" not in to_keep: +- full_cmd += "{} ".format(PATH) ++ full_cmd += f"{PATH} " + full_cmd += " ".join( +- [ +- "{}={}".format(x, pipes.quote(os.environ[x])) +- for x in to_keep +- if x in os.environ +- ] ++ [f"{x}={shlex.quote(os.environ[x])}" for x in to_keep if x in os.environ] + ) +- full_cmd += " {}".format(cmd) ++ full_cmd += f" {cmd}" + elif exec_driver == "docker-exec": + # We're using docker exec on the CLI as opposed to via docker-py, since + # the Docker API doesn't return stdout and stderr separately. + full_cmd = "docker exec " + if stdin: + full_cmd += "-i " +- full_cmd += "{} ".format(name) ++ full_cmd += f"{name} " + if keep_env is not True: + full_cmd += "env -i " + if "PATH" not in to_keep: +- full_cmd += "{} ".format(PATH) ++ full_cmd += f"{PATH} " + full_cmd += " ".join( +- [ +- "{}={}".format(x, pipes.quote(os.environ[x])) +- for x in to_keep +- if x in os.environ +- ] ++ [f"{x}={shlex.quote(os.environ[x])}" for x in to_keep if x in os.environ] + ) +- full_cmd += " {}".format(cmd) ++ full_cmd += f" {cmd}" + + if not use_vt: + ret = __salt__[cmd_func]( +@@ -299,13 +289,13 @@ def copy_to( + salt myminion container_resource.copy_to mycontainer /local/file/path /container/file/path container_type=docker exec_driver=nsenter + """ + # Get the appropriate functions +- state = __salt__["{}.state".format(container_type)] ++ state = __salt__[f"{container_type}.state"] + + def run_all(*args, **akwargs): + akwargs = copy.deepcopy(akwargs) + if container_type in ["lxc"] and "path" not in akwargs: + akwargs["path"] = path +- return __salt__["{}.run_all".format(container_type)](*args, **akwargs) ++ return __salt__[f"{container_type}.run_all"](*args, **akwargs) + + state_kwargs = {} + cmd_kwargs = {"ignore_retcode": True} +@@ -321,7 +311,7 @@ def copy_to( + + c_state = _state(name) + if c_state != "running": +- raise CommandExecutionError("Container '{}' is not running".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is not running") + + local_file = cache_file(source) + source_dir, source_name = os.path.split(local_file) +@@ -330,17 +320,14 @@ def copy_to( + if not os.path.isabs(local_file): + raise SaltInvocationError("Source path must be absolute") + elif not os.path.exists(local_file): +- raise SaltInvocationError("Source file {} does not exist".format(local_file)) ++ raise SaltInvocationError(f"Source file {local_file} does not exist") + elif not os.path.isfile(local_file): + raise SaltInvocationError("Source must be a regular file") + + # Destination file sanity checks + if not os.path.isabs(dest): + raise SaltInvocationError("Destination path must be absolute") +- if ( +- run_all(name, "test -d {}".format(pipes.quote(dest)), **cmd_kwargs)["retcode"] +- == 0 +- ): ++ if run_all(name, f"test -d {shlex.quote(dest)}", **cmd_kwargs)["retcode"] == 0: + # Destination is a directory, full path to dest file will include the + # basename of the source file. + dest = os.path.join(dest, source_name) +@@ -350,14 +337,12 @@ def copy_to( + # parent directory. + dest_dir, dest_name = os.path.split(dest) + if ( +- run_all(name, "test -d {}".format(pipes.quote(dest_dir)), **cmd_kwargs)[ +- "retcode" +- ] ++ run_all(name, f"test -d {shlex.quote(dest_dir)}", **cmd_kwargs)["retcode"] + != 0 + ): + if makedirs: + result = run_all( +- name, "mkdir -p {}".format(pipes.quote(dest_dir)), **cmd_kwargs ++ name, f"mkdir -p {shlex.quote(dest_dir)}", **cmd_kwargs + ) + if result["retcode"] != 0: + error = ( +@@ -375,10 +360,7 @@ def copy_to( + ) + if ( + not overwrite +- and run_all(name, "test -e {}".format(pipes.quote(dest)), **cmd_kwargs)[ +- "retcode" +- ] +- == 0 ++ and run_all(name, f"test -e {shlex.quote(dest)}", **cmd_kwargs)["retcode"] == 0 + ): + raise CommandExecutionError( + "Destination path {} already exists. Use overwrite=True to " +@@ -401,14 +383,14 @@ def copy_to( + if exec_driver == "lxc-attach": + lxcattach = "lxc-attach" + if path: +- lxcattach += " -P {}".format(pipes.quote(path)) ++ lxcattach += f" -P {shlex.quote(path)}" + copy_cmd = ( + 'cat "{0}" | {4} --clear-env --set-var {1} -n {2} -- tee "{3}"'.format( + local_file, PATH, name, dest, lxcattach + ) + ) + elif exec_driver == "nsenter": +- pid = __salt__["{}.pid".format(container_type)](name) ++ pid = __salt__[f"{container_type}.pid"](name) + copy_cmd = 'cat "{}" | {} env -i {} tee "{}"'.format( + local_file, _nsenter(pid), PATH, dest + ) +diff --git a/salt/modules/deb_postgres.py b/salt/modules/deb_postgres.py +index 3ecd4a8ba4..d92859562d 100644 +--- a/salt/modules/deb_postgres.py ++++ b/salt/modules/deb_postgres.py +@@ -2,10 +2,8 @@ + Module to provide Postgres compatibility to salt for debian family specific tools. + + """ +- +- + import logging +-import pipes ++import shlex + + import salt.utils.path + +@@ -76,7 +74,7 @@ def cluster_create( + cmd += ["--data-checksums"] + if wal_segsize: + cmd += ["--wal-segsize", wal_segsize] +- cmdstr = " ".join([pipes.quote(c) for c in cmd]) ++ cmdstr = " ".join([shlex.quote(c) for c in 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) +@@ -97,7 +95,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([pipes.quote(c) for c in cmd])) ++ ret = __salt__["cmd.run_all"](" ".join([shlex.quote(c) for c in cmd])) + if ret.get("retcode", 0) != 0: + log.error("Error listing clusters") + cluster_dict = _parse_pg_lscluster(ret["stdout"]) +@@ -118,7 +116,7 @@ def cluster_exists(version, name="main"): + + salt '*' postgres.cluster_exists '9.3' 'main' + """ +- return "{}/{}".format(version, name) in cluster_list() ++ return f"{version}/{name}" in cluster_list() + + + def cluster_remove(version, name="main", stop=False): +@@ -141,13 +139,13 @@ def cluster_remove(version, name="main", stop=False): + if stop: + cmd += ["--stop"] + cmd += [str(version), name] +- cmdstr = " ".join([pipes.quote(c) for c in cmd]) ++ cmdstr = " ".join([shlex.quote(c) for c in cmd]) + ret = __salt__["cmd.run_all"](cmdstr, python_shell=False) + # FIXME - return Boolean ? + if ret.get("retcode", 0) != 0: + log.error("Error removing a Postgresql cluster %s/%s", version, name) + else: +- ret["changes"] = "Successfully removed cluster {}/{}".format(version, name) ++ ret["changes"] = f"Successfully removed cluster {version}/{name}" + return ret + + +@@ -158,7 +156,7 @@ def _parse_pg_lscluster(output): + cluster_dict = {} + for line in output.splitlines(): + version, name, port, status, user, datadir, log = line.split() +- cluster_dict["{}/{}".format(version, name)] = { ++ cluster_dict[f"{version}/{name}"] = { + "port": int(port), + "status": status, + "user": user, +diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py +index 3e35700788..b58fd1b32b 100644 +--- a/salt/modules/dockermod.py ++++ b/salt/modules/dockermod.py +@@ -204,8 +204,8 @@ import gzip + import json + import logging + import os +-import pipes + import re ++import shlex + import shutil + import string + import subprocess +@@ -252,7 +252,6 @@ except ImportError: + + HAS_NSENTER = bool(salt.utils.path.which("nsenter")) + +-# Set up logging + log = logging.getLogger(__name__) + + # Don't shadow built-in's. +@@ -392,7 +391,7 @@ def _get_client(timeout=NOTSET, **kwargs): + ) + except Exception as exc: # pylint: disable=broad-except + raise CommandExecutionError( +- "Docker machine {} failed: {}".format(docker_machine, exc) ++ f"Docker machine {docker_machine} failed: {exc}" + ) + try: + # docker-py 2.0 renamed this client attribute +@@ -492,7 +491,7 @@ def _change_state(name, action, expected, *args, **kwargs): + return { + "result": False, + "state": {"old": expected, "new": expected}, +- "comment": "Container '{}' already {}".format(name, expected), ++ "comment": f"Container '{name}' already {expected}", + } + _client_wrapper(action, name, *args, **kwargs) + _clear_context() +@@ -530,9 +529,7 @@ def _get_md5(name, path): + """ + Get the MD5 checksum of a file from a container + """ +- output = run_stdout( +- name, "md5sum {}".format(pipes.quote(path)), ignore_retcode=True +- ) ++ output = run_stdout(name, f"md5sum {shlex.quote(path)}", ignore_retcode=True) + try: + return output.split()[0] + except IndexError: +@@ -611,7 +608,7 @@ def _scrub_links(links, name): + if isinstance(links, list): + ret = [] + for l in links: +- ret.append(l.replace("/{}/".format(name), "/", 1)) ++ ret.append(l.replace(f"/{name}/", "/", 1)) + else: + ret = links + +@@ -634,11 +631,11 @@ def _size_fmt(num): + try: + num = int(num) + if num < 1024: +- return "{} bytes".format(num) ++ return f"{num} bytes" + num /= 1024.0 + for unit in ("KiB", "MiB", "GiB", "TiB", "PiB"): + if num < 1024.0: +- return "{:3.1f} {}".format(num, unit) ++ return f"{num:3.1f} {unit}" + num /= 1024.0 + except Exception: # pylint: disable=broad-except + log.error("Unable to format file size for '%s'", num) +@@ -653,7 +650,7 @@ def _client_wrapper(attr, *args, **kwargs): + catch_api_errors = kwargs.pop("catch_api_errors", True) + func = getattr(__context__["docker.client"], attr, None) + if func is None or not hasattr(func, "__call__"): +- raise SaltInvocationError("Invalid client action '{}'".format(attr)) ++ raise SaltInvocationError(f"Invalid client action '{attr}'") + if attr in ("push", "pull"): + try: + # Refresh auth config from config.json +@@ -673,7 +670,7 @@ def _client_wrapper(attr, *args, **kwargs): + if catch_api_errors: + # Generic handling of Docker API errors + raise CommandExecutionError( +- "Error {}: {}".format(exc.response.status_code, exc.explanation) ++ f"Error {exc.response.status_code}: {exc.explanation}" + ) + else: + # Allow API errors to be caught further up the stack +@@ -688,9 +685,9 @@ def _client_wrapper(attr, *args, **kwargs): + + # If we're here, it's because an exception was caught earlier, and the + # API command failed. +- msg = "Unable to perform {}".format(attr) ++ msg = f"Unable to perform {attr}" + if err: +- msg += ": {}".format(err) ++ msg += f": {err}" + raise CommandExecutionError(msg) + + +@@ -717,7 +714,7 @@ def _import_status(data, item, repo_name, repo_tag): + return + elif all(x in string.hexdigits for x in status): + # Status is an image ID +- data["Image"] = "{}:{}".format(repo_name, repo_tag) ++ data["Image"] = f"{repo_name}:{repo_tag}" + data["Id"] = status + except (AttributeError, TypeError): + pass +@@ -876,7 +873,7 @@ def _get_create_kwargs( + ignore_collisions=False, + validate_ip_addrs=True, + client_args=None, +- **kwargs ++ **kwargs, + ): + """ + Take input kwargs and return a kwargs dict to pass to docker-py's +@@ -894,7 +891,7 @@ def _get_create_kwargs( + skip_translate=skip_translate, + ignore_collisions=ignore_collisions, + validate_ip_addrs=validate_ip_addrs, +- **__utils__["args.clean_kwargs"](**kwargs) ++ **__utils__["args.clean_kwargs"](**kwargs), + ) + + if networks: +@@ -907,7 +904,7 @@ def _get_create_kwargs( + log.error( + "docker.create: Error getting client args: '%s'", exc, exc_info=True + ) +- raise CommandExecutionError("Failed to get client args: {}".format(exc)) ++ raise CommandExecutionError(f"Failed to get client args: {exc}") + + full_host_config = {} + host_kwargs = {} +@@ -1468,15 +1465,15 @@ def login(*registries): + results = ret.setdefault("Results", {}) + for registry in registries: + if registry not in registry_auth: +- errors.append("No match found for registry '{}'".format(registry)) ++ errors.append(f"No match found for registry '{registry}'") + continue + try: + username = registry_auth[registry]["username"] + password = registry_auth[registry]["password"] + except TypeError: +- errors.append("Invalid configuration for registry '{}'".format(registry)) ++ errors.append(f"Invalid configuration for registry '{registry}'") + except KeyError as exc: +- errors.append("Missing {} for registry '{}'".format(exc, registry)) ++ errors.append(f"Missing {exc} for registry '{registry}'") + else: + cmd = ["docker", "login", "-u", username, "-p", password] + if registry.lower() != "hub": +@@ -1562,7 +1559,7 @@ def logout(*registries): + results = ret.setdefault("Results", {}) + for registry in registries: + if registry not in registry_auth: +- errors.append("No match found for registry '{}'".format(registry)) ++ errors.append(f"No match found for registry '{registry}'") + continue + else: + cmd = ["docker", "logout"] +@@ -1684,7 +1681,7 @@ def exists(name): + + salt myminion docker.exists mycontainer + """ +- contextkey = "docker.exists.{}".format(name) ++ contextkey = f"docker.exists.{name}" + if contextkey in __context__: + return __context__[contextkey] + try: +@@ -1775,7 +1772,7 @@ def history(name, quiet=False): + ) + for param in ("Size",): + if param in step: +- step["{}_Human".format(param)] = _size_fmt(step[param]) ++ step[f"{param}_Human"] = _size_fmt(step[param]) + ret.append(copy.deepcopy(step)) + if quiet: + return [x.get("Command") for x in ret] +@@ -1837,9 +1834,7 @@ def images(verbose=False, **kwargs): + ) + for param in ("Size", "VirtualSize"): + if param in bucket.get(img_id, {}): +- bucket[img_id]["{}_Human".format(param)] = _size_fmt( +- bucket[img_id][param] +- ) ++ bucket[img_id][f"{param}_Human"] = _size_fmt(bucket[img_id][param]) + + context_data = __context__.get("docker.images", {}) + ret = copy.deepcopy(context_data.get("tagged", {})) +@@ -1922,7 +1917,7 @@ def inspect(name): + raise + + raise CommandExecutionError( +- "Error 404: No such image/container/volume/network: {}".format(name) ++ f"Error 404: No such image/container/volume/network: {name}" + ) + + +@@ -1978,7 +1973,7 @@ def inspect_image(name): + ret = _client_wrapper("inspect_image", name) + for param in ("Size", "VirtualSize"): + if param in ret: +- ret["{}_Human".format(param)] = _size_fmt(ret[param]) ++ ret[f"{param}_Human"] = _size_fmt(ret[param]) + return ret + + +@@ -2272,7 +2267,7 @@ def port(name, private_port=None): + else: + # Sanity checks + if isinstance(private_port, int): +- pattern = "{}/*".format(private_port) ++ pattern = f"{private_port}/*" + else: + err = ( + "Invalid private_port '{}'. Must either be a port number, " +@@ -2393,7 +2388,7 @@ def state(name): + + salt myminion docker.state mycontainer + """ +- contextkey = "docker.state.{}".format(name) ++ contextkey = f"docker.state.{name}" + if contextkey in __context__: + return __context__[contextkey] + __context__[contextkey] = _get_state(inspect_container(name)) +@@ -2433,9 +2428,7 @@ def search(name, official=False, trusted=False): + """ + response = _client_wrapper("search", name) + if not response: +- raise CommandExecutionError( +- "No images matched the search string '{}'".format(name) +- ) ++ raise CommandExecutionError(f"No images matched the search string '{name}'") + + key_map = { + "description": "Description", +@@ -2550,7 +2543,7 @@ def create( + ignore_collisions=False, + validate_ip_addrs=True, + client_timeout=salt.utils.dockermod.CLIENT_TIMEOUT, +- **kwargs ++ **kwargs, + ): + """ + Create a new container +@@ -3276,7 +3269,7 @@ def create( + skip_translate=skip_translate, + ignore_collisions=ignore_collisions, + validate_ip_addrs=validate_ip_addrs, +- **kwargs ++ **kwargs, + ) + + if unused_kwargs: +@@ -3288,7 +3281,7 @@ def create( + + log.debug( + "docker.create: creating container %susing the following arguments: %s", +- "with name '{}' ".format(name) if name is not None else "", ++ f"with name '{name}' " if name is not None else "", + kwargs, + ) + time_started = time.time() +@@ -3326,7 +3319,7 @@ def run_container( + replace=False, + force=False, + networks=None, +- **kwargs ++ **kwargs, + ): + """ + .. versionadded:: 2018.3.0 +@@ -3428,7 +3421,7 @@ def run_container( + skip_translate=skip_translate, + ignore_collisions=ignore_collisions, + validate_ip_addrs=validate_ip_addrs, +- **kwargs ++ **kwargs, + ) + + # _get_create_kwargs() will have processed auto_remove and put it into the +@@ -3453,7 +3446,7 @@ def run_container( + + log.debug( + "docker.create: creating container %susing the following arguments: %s", +- "with name '{}' ".format(name) if name is not None else "", ++ f"with name '{name}' " if name is not None else "", + kwargs, + ) + +@@ -3493,7 +3486,7 @@ def run_container( + rm_(name) + except CommandExecutionError as rm_exc: + exc_info.setdefault("other_errors", []).append( +- "Failed to auto_remove container: {}".format(rm_exc) ++ f"Failed to auto_remove container: {rm_exc}" + ) + # Raise original exception with additional info + raise CommandExecutionError(exc.__str__(), info=exc_info) +@@ -3588,7 +3581,7 @@ def copy_from(name, source, dest, overwrite=False, makedirs=False): + """ + c_state = state(name) + if c_state != "running": +- raise CommandExecutionError("Container '{}' is not running".format(name)) ++ raise CommandExecutionError(f"Container '{name}' is not running") + + # Destination file sanity checks + if not os.path.isabs(dest): +@@ -3614,9 +3607,7 @@ def copy_from(name, source, dest, overwrite=False, makedirs=False): + ) + ) + else: +- raise SaltInvocationError( +- "Directory {} does not exist".format(dest_dir) +- ) ++ raise SaltInvocationError(f"Directory {dest_dir} does not exist") + if not overwrite and os.path.exists(dest): + raise CommandExecutionError( + "Destination path {} already exists. Use overwrite=True to " +@@ -3627,19 +3618,14 @@ def copy_from(name, source, dest, overwrite=False, makedirs=False): + if not os.path.isabs(source): + raise SaltInvocationError("Source path must be absolute") + else: +- if ( +- retcode(name, "test -e {}".format(pipes.quote(source)), ignore_retcode=True) +- == 0 +- ): ++ if retcode(name, f"test -e {shlex.quote(source)}", ignore_retcode=True) == 0: + if ( +- retcode( +- name, "test -f {}".format(pipes.quote(source)), ignore_retcode=True +- ) ++ retcode(name, f"test -f {shlex.quote(source)}", ignore_retcode=True) + != 0 + ): + raise SaltInvocationError("Source must be a regular file") + else: +- raise SaltInvocationError("Source file {} does not exist".format(source)) ++ raise SaltInvocationError(f"Source file {source} does not exist") + + # Before we try to replace the file, compare checksums. + source_md5 = _get_md5(name, source) +@@ -3652,7 +3638,7 @@ def copy_from(name, source, dest, overwrite=False, makedirs=False): + try: + src_path = ":".join((name, source)) + except TypeError: +- src_path = "{}:{}".format(name, source) ++ src_path = f"{name}:{source}" + cmd = ["docker", "cp", src_path, dest_dir] + __salt__["cmd.run"](cmd, python_shell=False) + return source_md5 == __salt__["file.get_sum"](dest, "md5") +@@ -3779,7 +3765,7 @@ def export(name, path, overwrite=False, makedirs=False, compression=None, **kwar + salt myminion docker.export mycontainer /tmp/mycontainer.tar + salt myminion docker.export mycontainer /tmp/mycontainer.tar.xz push=True + """ +- err = "Path '{}' is not absolute".format(path) ++ err = f"Path '{path}' is not absolute" + try: + if not os.path.isabs(path): + raise SaltInvocationError(err) +@@ -3787,7 +3773,7 @@ def export(name, path, overwrite=False, makedirs=False, compression=None, **kwar + raise SaltInvocationError(err) + + if os.path.exists(path) and not overwrite: +- raise CommandExecutionError("{} already exists".format(path)) ++ raise CommandExecutionError(f"{path} already exists") + + if compression is None: + if path.endswith(".tar.gz") or path.endswith(".tgz"): +@@ -3810,7 +3796,7 @@ def export(name, path, overwrite=False, makedirs=False, compression=None, **kwar + compression = "xz" + + if compression and compression not in ("gzip", "bzip2", "xz"): +- raise SaltInvocationError("Invalid compression type '{}'".format(compression)) ++ raise SaltInvocationError(f"Invalid compression type '{compression}'") + + parent_dir = os.path.dirname(path) + if not os.path.isdir(parent_dir): +@@ -3823,16 +3809,14 @@ def export(name, path, overwrite=False, makedirs=False, compression=None, **kwar + os.makedirs(parent_dir) + except OSError as exc: + raise CommandExecutionError( +- "Unable to make parent dir {}: {}".format(parent_dir, exc) ++ f"Unable to make parent dir {parent_dir}: {exc}" + ) + + if compression == "gzip": + try: + out = gzip.open(path, "wb") + except OSError as exc: +- raise CommandExecutionError( +- "Unable to open {} for writing: {}".format(path, exc) +- ) ++ raise CommandExecutionError(f"Unable to open {path} for writing: {exc}") + elif compression == "bzip2": + compressor = bz2.BZ2Compressor() + elif compression == "xz": +@@ -3870,9 +3854,7 @@ def export(name, path, overwrite=False, makedirs=False, compression=None, **kwar + os.remove(path) + except OSError: + pass +- raise CommandExecutionError( +- "Error occurred during container export: {}".format(exc) +- ) ++ raise CommandExecutionError(f"Error occurred during container export: {exc}") + finally: + out.close() + ret = {"Time_Elapsed": time.time() - time_started} +@@ -4103,7 +4085,7 @@ def build( + # For the build function in the low-level API, the "tag" refers to the full + # tag (e.g. myuser/myimage:mytag). This is different than in other + # functions, where the repo and tag are passed separately. +- image_tag = "{}:{}".format(repository, tag) if repository and tag else None ++ image_tag = f"{repository}:{tag}" if repository and tag else None + + time_started = time.time() + response = _client_wrapper( +@@ -4122,7 +4104,7 @@ def build( + + if not response: + raise CommandExecutionError( +- "Build failed for {}, no response returned from Docker API".format(path) ++ f"Build failed for {path}, no response returned from Docker API" + ) + + stream_data = [] +@@ -4145,7 +4127,7 @@ def build( + if "Id" not in ret: + # API returned information, but there was no confirmation of a + # successful build. +- msg = "Build failed for {}".format(path) ++ msg = f"Build failed for {path}" + log.error(msg) + log.error(stream_data) + if errors: +@@ -4156,7 +4138,7 @@ def build( + if resolved_tag: + ret["Image"] = resolved_tag + else: +- ret["Warning"] = "Failed to tag image as {}".format(image_tag) ++ ret["Warning"] = f"Failed to tag image as {image_tag}" + + if api_response: + ret["API_Response"] = stream_data +@@ -4363,7 +4345,7 @@ def import_(source, repository, tag="latest", api_response=False): + + if not response: + raise CommandExecutionError( +- "Import failed for {}, no response returned from Docker API".format(source) ++ f"Import failed for {source}, no response returned from Docker API" + ) + elif api_response: + ret["API_Response"] = response +@@ -4383,7 +4365,7 @@ def import_(source, repository, tag="latest", api_response=False): + if "Id" not in ret: + # API returned information, but there was no confirmation of a + # successful push. +- msg = "Import failed for {}".format(source) ++ msg = f"Import failed for {source}" + if errors: + msg += ". Error(s) follow:\n\n{}".format("\n\n".join(errors)) + raise CommandExecutionError(msg) +@@ -4458,7 +4440,7 @@ def load(path, repository=None, tag=None): + + local_path = __salt__["container_resource.cache_file"](path) + if not os.path.isfile(local_path): +- raise CommandExecutionError("Source file {} does not exist".format(path)) ++ raise CommandExecutionError(f"Source file {path} does not exist") + + pre = images(all=True) + cmd = ["docker", "load", "-i", local_path] +@@ -4468,7 +4450,7 @@ def load(path, repository=None, tag=None): + _clear_context() + post = images(all=True) + if result["retcode"] != 0: +- msg = "Failed to load image(s) from {}".format(path) ++ msg = f"Failed to load image(s) from {path}" + if result["stderr"]: + msg += ": {}".format(result["stderr"]) + raise CommandExecutionError(msg) +@@ -4489,7 +4471,7 @@ def load(path, repository=None, tag=None): + # strings when passed (e.g. a numeric tag would be loaded as an int + # or float), and because the tag_ function will stringify them if + # need be, a str.format is the correct thing to do here. +- tagged_image = "{}:{}".format(repository, tag) ++ tagged_image = f"{repository}:{tag}" + try: + result = tag_(top_level_images[0], repository=repository, tag=tag) + ret["Image"] = tagged_image +@@ -4526,7 +4508,7 @@ def layers(name): + ): + ret.append(line) + if not ret: +- raise CommandExecutionError("Image '{}' not found".format(name)) ++ raise CommandExecutionError(f"Image '{name}' not found") + return ret + + +@@ -4597,7 +4579,7 @@ def pull( + + if not response: + raise CommandExecutionError( +- "Pull failed for {}, no response returned from Docker API".format(image) ++ f"Pull failed for {image}, no response returned from Docker API" + ) + elif api_response: + ret["API_Response"] = response +@@ -4610,7 +4592,7 @@ def pull( + event = salt.utils.json.loads(event) + except Exception as exc: # pylint: disable=broad-except + raise CommandExecutionError( +- "Unable to interpret API event: '{}'".format(event), ++ f"Unable to interpret API event: '{event}'", + info={"Error": exc.__str__()}, + ) + try: +@@ -4692,7 +4674,7 @@ def push( + + if not response: + raise CommandExecutionError( +- "Push failed for {}, no response returned from Docker API".format(image) ++ f"Push failed for {image}, no response returned from Docker API" + ) + elif api_response: + ret["API_Response"] = response +@@ -4704,7 +4686,7 @@ def push( + event = salt.utils.json.loads(event) + except Exception as exc: # pylint: disable=broad-except + raise CommandExecutionError( +- "Unable to interpret API event: '{}'".format(event), ++ f"Unable to interpret API event: '{event}'", + info={"Error": exc.__str__()}, + ) + try: +@@ -4784,9 +4766,7 @@ def rmi(*names, **kwargs): + err += "image(s): {}".format(", ".join(deps["Images"])) + errors.append(err) + else: +- errors.append( +- "Error {}: {}".format(exc.response.status_code, exc.explanation) +- ) ++ errors.append(f"Error {exc.response.status_code}: {exc.explanation}") + + _clear_context() + ret = { +@@ -4874,7 +4854,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + salt myminion docker.save centos:7 /tmp/cent7.tar + salt myminion docker.save 0123456789ab cdef01234567 /tmp/saved.tar + """ +- err = "Path '{}' is not absolute".format(path) ++ err = f"Path '{path}' is not absolute" + try: + if not os.path.isabs(path): + raise SaltInvocationError(err) +@@ -4882,7 +4862,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + raise SaltInvocationError(err) + + if os.path.exists(path) and not overwrite: +- raise CommandExecutionError("{} already exists".format(path)) ++ raise CommandExecutionError(f"{path} already exists") + + if compression is None: + if path.endswith(".tar.gz") or path.endswith(".tgz"): +@@ -4905,7 +4885,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + compression = "xz" + + if compression and compression not in ("gzip", "bzip2", "xz"): +- raise SaltInvocationError("Invalid compression type '{}'".format(compression)) ++ raise SaltInvocationError(f"Invalid compression type '{compression}'") + + parent_dir = os.path.dirname(path) + if not os.path.isdir(parent_dir): +@@ -4927,7 +4907,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + time_started = time.time() + result = __salt__["cmd.run_all"](cmd, python_shell=False) + if result["retcode"] != 0: +- err = "Failed to save image(s) to {}".format(path) ++ err = f"Failed to save image(s) to {path}" + if result["stderr"]: + err += ": {}".format(result["stderr"]) + raise CommandExecutionError(err) +@@ -4937,9 +4917,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + try: + out = gzip.open(path, "wb") + except OSError as exc: +- raise CommandExecutionError( +- "Unable to open {} for writing: {}".format(path, exc) +- ) ++ raise CommandExecutionError(f"Unable to open {path} for writing: {exc}") + elif compression == "bzip2": + compressor = bz2.BZ2Compressor() + elif compression == "xz": +@@ -4975,9 +4953,7 @@ def save(name, path, overwrite=False, makedirs=False, compression=None, **kwargs + os.remove(path) + except OSError: + pass +- raise CommandExecutionError( +- "Error occurred during image save: {}".format(exc) +- ) ++ raise CommandExecutionError(f"Error occurred during image save: {exc}") + finally: + try: + # Clean up temp file +@@ -5097,7 +5073,7 @@ def create_network( + ignore_collisions=False, + validate_ip_addrs=True, + client_timeout=salt.utils.dockermod.CLIENT_TIMEOUT, +- **kwargs ++ **kwargs, + ): + """ + .. versionchanged:: 2018.3.0 +@@ -5337,7 +5313,7 @@ def create_network( + skip_translate=skip_translate, + ignore_collisions=ignore_collisions, + validate_ip_addrs=validate_ip_addrs, +- **__utils__["args.clean_kwargs"](**kwargs) ++ **__utils__["args.clean_kwargs"](**kwargs), + ) + + if "ipam" not in kwargs: +@@ -5669,7 +5645,7 @@ def pause(name): + return { + "result": False, + "state": {"old": orig_state, "new": orig_state}, +- "comment": "Container '{}' is stopped, cannot pause".format(name), ++ "comment": f"Container '{name}' is stopped, cannot pause", + } + return _change_state(name, "pause", "paused") + +@@ -5768,7 +5744,7 @@ def start_(name): + return { + "result": False, + "state": {"old": orig_state, "new": orig_state}, +- "comment": "Container '{}' is paused, cannot start".format(name), ++ "comment": f"Container '{name}' is paused, cannot start", + } + + return _change_state(name, "start", "running") +@@ -5873,7 +5849,7 @@ def unpause(name): + return { + "result": False, + "state": {"old": orig_state, "new": orig_state}, +- "comment": "Container '{}' is stopped, cannot unpause".format(name), ++ "comment": f"Container '{name}' is stopped, cannot unpause", + } + return _change_state(name, "unpause", "running") + +@@ -5922,7 +5898,7 @@ def wait(name, ignore_already_stopped=False, fail_on_exit_status=False): + # Container doesn't exist anymore + return { + "result": ignore_already_stopped, +- "comment": "Container '{}' absent".format(name), ++ "comment": f"Container '{name}' absent", + } + already_stopped = pre == "stopped" + response = _client_wrapper("wait", name) +@@ -5946,7 +5922,7 @@ def wait(name, ignore_already_stopped=False, fail_on_exit_status=False): + "exit_status": response, + } + if already_stopped: +- result["comment"] = "Container '{}' already stopped".format(name) ++ result["comment"] = f"Container '{name}' already stopped" + if fail_on_exit_status and result["result"]: + result["result"] = result["exit_status"] == 0 + return result +@@ -5959,7 +5935,7 @@ def prune( + build=False, + volumes=False, + system=None, +- **filters ++ **filters, + ): + """ + .. versionadded:: 2019.2.0 +@@ -6645,7 +6621,7 @@ def script_retcode( + + + def _generate_tmp_path(): +- return os.path.join("/tmp", "salt.docker.{}".format(uuid.uuid4().hex[:6])) ++ return os.path.join("/tmp", f"salt.docker.{uuid.uuid4().hex[:6]}") + + + def _prepare_trans_tar(name, sls_opts, mods=None, pillar=None, extra_filerefs=""): +@@ -6780,7 +6756,7 @@ def call(name, function, *args, **kwargs): + ] + + list(args) + + [ +- "{}={}".format(key, value) ++ f"{key}={value}" + for (key, value) in kwargs.items() + if not key.startswith("__") + ] +diff --git a/salt/modules/lxc.py b/salt/modules/lxc.py +index 9d04963ba7..ba03d1f418 100644 +--- a/salt/modules/lxc.py ++++ b/salt/modules/lxc.py +@@ -12,9 +12,9 @@ import datetime + import difflib + import logging + import os +-import pipes + import random + import re ++import shlex + import shutil + import string + import tempfile +@@ -1834,7 +1834,7 @@ def _after_ignition_network_profile(cmd, ret, name, network_profile, path, nic_o + # destroy the container if it was partially created + cmd = "lxc-destroy" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {name}" + __salt__["cmd.retcode"](cmd, python_shell=False) + raise CommandExecutionError( +@@ -1997,7 +1997,7 @@ def create( + ) + options["imgtar"] = img_tar + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + if not os.path.exists(path): + os.makedirs(path) + if config: +@@ -2136,7 +2136,7 @@ def clone(name, orig, profile=None, network_profile=None, nic_opts=None, **kwarg + cmd = "lxc-clone" + cmd += f" {snapshot} -o {orig} -n {name}" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + if not os.path.exists(path): + os.makedirs(path) + if backing: +@@ -2184,7 +2184,7 @@ def ls_(active=None, cache=True, path=None): + ret = [] + cmd = "lxc-ls" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + if active: + cmd += " --active" + output = __salt__["cmd.run_stdout"](cmd, python_shell=False) +@@ -2240,7 +2240,7 @@ def list_(extra=False, limit=None, path=None): + for container in ctnrs: + cmd = "lxc-info" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {container}" + c_info = __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="debug") + c_state = None +@@ -2299,12 +2299,12 @@ def _change_state( + # Kill the container first + scmd = "lxc-stop" + if path: +- scmd += f" -P {pipes.quote(path)}" ++ scmd += f" -P {shlex.quote(path)}" + scmd += f" -k -n {name}" + __salt__["cmd.run"](scmd, python_shell=False) + + if path and " -P " not in cmd: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {name}" + + # certain lxc commands need to be taken with care (lxc-start) +@@ -2335,7 +2335,7 @@ def _change_state( + # some commands do not wait, so we will + rcmd = "lxc-wait" + if path: +- rcmd += f" -P {pipes.quote(path)}" ++ rcmd += f" -P {shlex.quote(path)}" + rcmd += f" -n {name} -s {expected.upper()}" + __salt__["cmd.run"](rcmd, python_shell=False, timeout=30) + _clear_context() +@@ -2457,7 +2457,7 @@ def start(name, **kwargs): + lxc_config = os.path.join(cpath, name, "config") + # we try to start, even without config, if global opts are there + if os.path.exists(lxc_config): +- cmd += f" -f {pipes.quote(lxc_config)}" ++ cmd += f" -f {shlex.quote(lxc_config)}" + cmd += " -d" + _ensure_exists(name, path=path) + if state(name, path=path) == "frozen": +@@ -2560,7 +2560,7 @@ def freeze(name, **kwargs): + start(name, path=path) + cmd = "lxc-freeze" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + ret = _change_state(cmd, name, "frozen", use_vt=use_vt, path=path) + if orig_state == "stopped" and start_: + ret["state"]["old"] = orig_state +@@ -2595,7 +2595,7 @@ def unfreeze(name, path=None, use_vt=None): + raise CommandExecutionError(f"Container '{name}' is stopped") + cmd = "lxc-unfreeze" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + return _change_state(cmd, name, "running", path=path, use_vt=use_vt) + + +@@ -2689,7 +2689,7 @@ def state(name, path=None): + else: + cmd = "lxc-info" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {name}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: +@@ -2727,7 +2727,7 @@ def get_parameter(name, parameter, path=None): + _ensure_exists(name, path=path) + cmd = "lxc-cgroup" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {name} {parameter}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: +@@ -2756,7 +2756,7 @@ def set_parameter(name, parameter, value, path=None): + + cmd = "lxc-cgroup" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" -n {name} {parameter} {value}" + ret = __salt__["cmd.run_all"](cmd, python_shell=False) + if ret["retcode"] != 0: +@@ -3648,7 +3648,7 @@ def attachable(name, path=None): + log.debug("Checking if LXC container %s is attachable", name) + cmd = "lxc-attach" + if path: +- cmd += f" -P {pipes.quote(path)}" ++ cmd += f" -P {shlex.quote(path)}" + cmd += f" --clear-env -n {name} -- /usr/bin/env" + result = ( + __salt__["cmd.retcode"]( +diff --git a/salt/modules/mac_keychain.py b/salt/modules/mac_keychain.py +index a823c428b7..7fdc162b9a 100644 +--- a/salt/modules/mac_keychain.py ++++ b/salt/modules/mac_keychain.py +@@ -11,20 +11,6 @@ import shlex + + import salt.utils.platform + +-try: +- import pipes +- +- HAS_DEPS = True +-except ImportError: +- HAS_DEPS = False +- +-if hasattr(shlex, "quote"): +- _quote = shlex.quote +-elif HAS_DEPS and hasattr(pipes, "quote"): +- _quote = pipes.quote +-else: +- _quote = None +- + log = logging.getLogger(__name__) + + __virtualname__ = "keychain" +@@ -34,7 +20,7 @@ def __virtual__(): + """ + Only work on Mac OS + """ +- if salt.utils.platform.is_darwin() and _quote is not None: ++ if salt.utils.platform.is_darwin(): + return __virtualname__ + return (False, "Only available on Mac OS systems with pipes") + +@@ -82,7 +68,7 @@ def install( + if keychain_password is not None: + unlock_keychain(keychain, keychain_password) + +- cmd = "security import {} -P {} -k {}".format(cert, password, keychain) ++ cmd = f"security import {cert} -P {password} -k {keychain}" + if allow_any: + cmd += " -A" + return __salt__["cmd.run"](cmd) +@@ -117,7 +103,7 @@ def uninstall( + if keychain_password is not None: + unlock_keychain(keychain, keychain_password) + +- cmd = 'security delete-certificate -c "{}" {}'.format(cert_name, keychain) ++ cmd = f'security delete-certificate -c "{cert_name}" {keychain}' + return __salt__["cmd.run"](cmd) + + +@@ -137,7 +123,7 @@ def list_certs(keychain="/Library/Keychains/System.keychain"): + """ + cmd = ( + 'security find-certificate -a {} | grep -o "alis".*\\" | ' +- "grep -o '\\\"[-A-Za-z0-9.:() ]*\\\"'".format(_quote(keychain)) ++ "grep -o '\\\"[-A-Za-z0-9.:() ]*\\\"'".format(shlex.quote(keychain)) + ) + out = __salt__["cmd.run"](cmd, python_shell=True) + return out.replace('"', "").split("\n") +@@ -165,7 +151,7 @@ def get_friendly_name(cert, password): + """ + cmd = ( + "openssl pkcs12 -in {} -passin pass:{} -info -nodes -nokeys 2> /dev/null | " +- "grep friendlyName:".format(_quote(cert), _quote(password)) ++ "grep friendlyName:".format(shlex.quote(cert), shlex.quote(password)) + ) + out = __salt__["cmd.run"](cmd, python_shell=True) + return out.replace("friendlyName: ", "").strip() +@@ -187,7 +173,7 @@ def get_default_keychain(user=None, domain="user"): + + salt '*' keychain.get_default_keychain + """ +- cmd = "security default-keychain -d {}".format(domain) ++ cmd = f"security default-keychain -d {domain}" + return __salt__["cmd.run"](cmd, runas=user) + + +@@ -210,7 +196,7 @@ def set_default_keychain(keychain, domain="user", user=None): + + salt '*' keychain.set_keychain /Users/fred/Library/Keychains/login.keychain + """ +- cmd = "security default-keychain -d {} -s {}".format(domain, keychain) ++ cmd = f"security default-keychain -d {domain} -s {keychain}" + return __salt__["cmd.run"](cmd, runas=user) + + +@@ -233,7 +219,7 @@ def unlock_keychain(keychain, password): + + salt '*' keychain.unlock_keychain /tmp/test.p12 test123 + """ +- cmd = "security unlock-keychain -p {} {}".format(password, keychain) ++ cmd = f"security unlock-keychain -p {password} {keychain}" + __salt__["cmd.run"](cmd) + + +@@ -261,7 +247,7 @@ def get_hash(name, password=None): + name, password + ) + else: +- cmd = 'security find-certificate -c "{}" -m -p'.format(name) ++ cmd = f'security find-certificate -c "{name}" -m -p' + + out = __salt__["cmd.run"](cmd) + matches = re.search( +diff --git a/salt/modules/macpackage.py b/salt/modules/macpackage.py +index faf5810d4f..f9a6b7bb95 100644 +--- a/salt/modules/macpackage.py ++++ b/salt/modules/macpackage.py +@@ -9,31 +9,16 @@ import shlex + + import salt.utils.platform + +-try: +- import pipes +- +- HAS_DEPS = True +-except ImportError: +- HAS_DEPS = False +- +- + log = logging.getLogger(__name__) +-__virtualname__ = "macpackage" +- + +-if hasattr(shlex, "quote"): +- _quote = shlex.quote +-elif HAS_DEPS and hasattr(pipes, "quote"): +- _quote = pipes.quote +-else: +- _quote = None ++__virtualname__ = "macpackage" + + + def __virtual__(): + """ + Only work on Mac OS + """ +- if salt.utils.platform.is_darwin() and _quote is not None: ++ if salt.utils.platform.is_darwin(): + return __virtualname__ + return (False, "Only available on Mac OS systems with pipes") + +@@ -60,11 +45,11 @@ def install(pkg, target="LocalSystem", store=False, allow_untrusted=False): + """ + if "*." not in pkg: + # If we use wildcards, we cannot use quotes +- pkg = _quote(pkg) ++ pkg = shlex.quote(pkg) + +- target = _quote(target) ++ target = shlex.quote(target) + +- cmd = "installer -pkg {} -target {}".format(pkg, target) ++ cmd = f"installer -pkg {pkg} -target {target}" + if store: + cmd += " -store" + if allow_untrusted: +@@ -109,7 +94,7 @@ def install_app(app, target="/Applications/"): + if not app[-1] == "/": + app += "/" + +- cmd = 'rsync -a --delete "{}" "{}"'.format(app, target) ++ cmd = f'rsync -a --delete "{app}" "{target}"' + return __salt__["cmd.run"](cmd) + + +@@ -154,7 +139,7 @@ def mount(dmg): + + temp_dir = __salt__["temp.dir"](prefix="dmg-") + +- cmd = 'hdiutil attach -readonly -nobrowse -mountpoint {} "{}"'.format(temp_dir, dmg) ++ cmd = f'hdiutil attach -readonly -nobrowse -mountpoint {temp_dir} "{dmg}"' + + return __salt__["cmd.run"](cmd), temp_dir + +@@ -176,7 +161,7 @@ def unmount(mountpoint): + salt '*' macpackage.unmount /dev/disk2 + """ + +- cmd = 'hdiutil detach "{}"'.format(mountpoint) ++ cmd = f'hdiutil detach "{mountpoint}"' + + return __salt__["cmd.run"](cmd) + +@@ -216,7 +201,7 @@ def get_pkg_id(pkg): + + salt '*' macpackage.get_pkg_id /tmp/test.pkg + """ +- pkg = _quote(pkg) ++ pkg = shlex.quote(pkg) + package_ids = [] + + # Create temp directory +@@ -224,7 +209,7 @@ def get_pkg_id(pkg): + + try: + # List all of the PackageInfo files +- cmd = "xar -t -f {} | grep PackageInfo".format(pkg) ++ cmd = f"xar -t -f {pkg} | grep PackageInfo" + out = __salt__["cmd.run"](cmd, python_shell=True, output_loglevel="quiet") + files = out.split("\n") + +@@ -264,12 +249,12 @@ def get_mpkg_ids(mpkg): + + salt '*' macpackage.get_mpkg_ids /dev/disk2 + """ +- mpkg = _quote(mpkg) ++ mpkg = shlex.quote(mpkg) + package_infos = [] + base_path = os.path.dirname(mpkg) + + # List all of the .pkg files +- cmd = "find {} -name *.pkg".format(base_path) ++ cmd = f"find {base_path} -name *.pkg" + out = __salt__["cmd.run"](cmd, python_shell=True) + + pkg_files = out.split("\n") +@@ -281,7 +266,7 @@ def get_mpkg_ids(mpkg): + + def _get_pkg_id_from_pkginfo(pkginfo): + # Find our identifiers +- pkginfo = _quote(pkginfo) ++ pkginfo = shlex.quote(pkginfo) + cmd = "cat {} | grep -Eo 'identifier=\"[a-zA-Z.0-9\\-]*\"' | cut -c 13- | tr -d '\"'".format( + pkginfo + ) +@@ -294,8 +279,8 @@ def _get_pkg_id_from_pkginfo(pkginfo): + + + def _get_pkg_id_dir(path): +- path = _quote(os.path.join(path, "Contents/Info.plist")) +- cmd = '/usr/libexec/PlistBuddy -c "print :CFBundleIdentifier" {}'.format(path) ++ path = shlex.quote(os.path.join(path, "Contents/Info.plist")) ++ cmd = f'/usr/libexec/PlistBuddy -c "print :CFBundleIdentifier" {path}' + + # We can only use wildcards in python_shell which is + # sent by the macpackage state +diff --git a/salt/modules/openstack_config.py b/salt/modules/openstack_config.py +index 823afbf1c6..937c10da61 100644 +--- a/salt/modules/openstack_config.py ++++ b/salt/modules/openstack_config.py +@@ -13,28 +13,11 @@ import shlex + import salt.exceptions + import salt.utils.decorators.path + +-try: +- import pipes +- +- HAS_DEPS = True +-except ImportError: +- HAS_DEPS = False +- +-if hasattr(shlex, "quote"): +- _quote = shlex.quote +-elif HAS_DEPS and hasattr(pipes, "quote"): +- _quote = pipes.quote +-else: +- _quote = None +- +- + # Don't shadow built-in's. + __func_alias__ = {"set_": "set"} + + + def __virtual__(): +- if _quote is None and not HAS_DEPS: +- return (False, "Missing dependencies") + return True + + +@@ -69,10 +52,10 @@ def set_(filename, section, parameter, value): + salt-call openstack_config.set /etc/keystone/keystone.conf sql connection foo + """ + +- filename = _quote(filename) +- section = _quote(section) +- parameter = _quote(parameter) +- value = _quote(str(value)) ++ filename = shlex.quote(filename) ++ section = shlex.quote(section) ++ parameter = shlex.quote(parameter) ++ value = shlex.quote(str(value)) + + result = __salt__["cmd.run_all"]( + "openstack-config --set {} {} {} {}".format( +@@ -109,12 +92,12 @@ def get(filename, section, parameter): + + """ + +- filename = _quote(filename) +- section = _quote(section) +- parameter = _quote(parameter) ++ filename = shlex.quote(filename) ++ section = shlex.quote(section) ++ parameter = shlex.quote(parameter) + + result = __salt__["cmd.run_all"]( +- "openstack-config --get {} {} {}".format(filename, section, parameter), ++ f"openstack-config --get {filename} {section} {parameter}", + python_shell=False, + ) + +@@ -145,12 +128,12 @@ def delete(filename, section, parameter): + salt-call openstack_config.delete /etc/keystone/keystone.conf sql connection + """ + +- filename = _quote(filename) +- section = _quote(section) +- parameter = _quote(parameter) ++ filename = shlex.quote(filename) ++ section = shlex.quote(section) ++ parameter = shlex.quote(parameter) + + result = __salt__["cmd.run_all"]( +- "openstack-config --del {} {} {}".format(filename, section, parameter), ++ f"openstack-config --del {filename} {section} {parameter}", + python_shell=False, + ) + +diff --git a/salt/modules/postgres.py b/salt/modules/postgres.py +index 25a72f1063..f73959a92e 100644 +--- a/salt/modules/postgres.py ++++ b/salt/modules/postgres.py +@@ -46,8 +46,8 @@ import hmac + import io + import logging + import os +-import pipes + import re ++import shlex + import tempfile + + import salt.utils.files +@@ -136,7 +136,7 @@ def __virtual__(): + for util in utils: + if not salt.utils.path.which(util): + if not _find_pg_binary(util): +- return (False, "{} was not found".format(util)) ++ return (False, f"{util} was not found") + return True + + +@@ -241,14 +241,14 @@ def _run_initdb( + raise CommandExecutionError("initdb executable not found.") + cmd = [ + _INITDB_BIN, +- "--pgdata={}".format(name), +- "--username={}".format(user), +- "--auth={}".format(auth), +- "--encoding={}".format(encoding), ++ f"--pgdata={name}", ++ f"--username={user}", ++ f"--auth={auth}", ++ f"--encoding={encoding}", + ] + + if locale is not None: +- cmd.append("--locale={}".format(locale)) ++ cmd.append(f"--locale={locale}") + + # intentionally use short option, as the long option name has been + # renamed from "xlogdir" to "waldir" in PostgreSQL 10 +@@ -262,9 +262,9 @@ def _run_initdb( + if password is not None: + pgpassfile = salt.utils.files.mkstemp(text=True) + with salt.utils.files.fopen(pgpassfile, "w") as fp_: +- fp_.write(salt.utils.stringutils.to_str("{}".format(password))) ++ fp_.write(salt.utils.stringutils.to_str(f"{password}")) + __salt__["file.chown"](pgpassfile, runas, "") +- cmd.extend(["--pwfile={}".format(pgpassfile)]) ++ cmd.extend([f"--pwfile={pgpassfile}"]) + + kwargs = dict( + runas=runas, +@@ -273,7 +273,7 @@ def _run_initdb( + "postgres.timeout", default=_DEFAULT_COMMAND_TIMEOUT_SECS + ), + ) +- cmdstr = " ".join([pipes.quote(c) for c in cmd]) ++ cmdstr = " ".join([shlex.quote(c) for c in cmd]) + ret = __salt__["cmd.run_all"](cmdstr, python_shell=False, **kwargs) + + if ret.get("retcode", 0) != 0: +@@ -582,9 +582,7 @@ def _quote_ddl_value(value, quote="'"): + if value is None: + return None + if quote in value: # detect trivial sqli +- raise SaltInvocationError( +- "Unsupported character {} in value: {}".format(quote, value) +- ) ++ raise SaltInvocationError(f"Unsupported character {quote} in value: {value}") + return "{quote}{value}{quote}".format(quote=quote, value=value) + + +@@ -617,7 +615,7 @@ def db_create( + """ + + # Base query to create a database +- query = 'CREATE DATABASE "{}"'.format(name) ++ query = f'CREATE DATABASE "{name}"' + + # "With"-options to create a database + with_args = salt.utils.odict.OrderedDict( +@@ -685,11 +683,9 @@ def db_alter( + else: + queries = [] + if owner: +- queries.append('ALTER DATABASE "{}" OWNER TO "{}"'.format(name, owner)) ++ queries.append(f'ALTER DATABASE "{name}" OWNER TO "{owner}"') + if tablespace: +- queries.append( +- 'ALTER DATABASE "{}" SET TABLESPACE "{}"'.format(name, tablespace) +- ) ++ queries.append(f'ALTER DATABASE "{name}" SET TABLESPACE "{tablespace}"') + for query in queries: + ret = _psql_prepare_and_run( + ["-c", query], +@@ -726,10 +722,10 @@ def db_remove( + salt '*' postgres.db_remove 'dbname' + """ + for query in [ +- 'REVOKE CONNECT ON DATABASE "{db}" FROM public;'.format(db=name), ++ f'REVOKE CONNECT ON DATABASE "{name}" FROM public;', + "SELECT pid, pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname =" + " '{db}' AND pid <> pg_backend_pid();".format(db=name), +- 'DROP DATABASE "{db}";'.format(db=name), ++ f'DROP DATABASE "{name}";', + ]: + ret = _psql_prepare_and_run( + ["-c", query], +@@ -741,7 +737,7 @@ def db_remove( + password=password, + ) + if ret["retcode"] != 0: +- raise Exception("Failed: ret={}".format(ret)) ++ raise Exception(f"Failed: ret={ret}") + return True + + +@@ -846,10 +842,10 @@ def tablespace_create( + owner_query = "" + options_query = "" + if owner: +- owner_query = 'OWNER "{}"'.format(owner) ++ owner_query = f'OWNER "{owner}"' + # should come out looking like: 'OWNER postgres' + if options: +- optionstext = ["{} = {}".format(k, v) for k, v in options.items()] ++ optionstext = [f"{k} = {v}" for k, v in options.items()] + options_query = "WITH ( {} )".format(", ".join(optionstext)) + # should come out looking like: 'WITH ( opt1 = 1.0, opt2 = 4.0 )' + query = "CREATE TABLESPACE \"{}\" {} LOCATION '{}' {}".format( +@@ -902,9 +898,9 @@ def tablespace_alter( + queries = [] + + if new_name: +- queries.append('ALTER TABLESPACE "{}" RENAME TO "{}"'.format(name, new_name)) ++ queries.append(f'ALTER TABLESPACE "{name}" RENAME TO "{new_name}"') + if new_owner: +- queries.append('ALTER TABLESPACE "{}" OWNER TO "{}"'.format(name, new_owner)) ++ queries.append(f'ALTER TABLESPACE "{name}" OWNER TO "{new_owner}"') + if set_option: + queries.append( + 'ALTER TABLESPACE "{}" SET ({} = {})'.format( +@@ -912,7 +908,7 @@ def tablespace_alter( + ) + ) + if reset_option: +- queries.append('ALTER TABLESPACE "{}" RESET ({})'.format(name, reset_option)) ++ queries.append(f'ALTER TABLESPACE "{name}" RESET ({reset_option})') + + for query in queries: + ret = _psql_prepare_and_run( +@@ -950,7 +946,7 @@ def tablespace_remove( + + .. versionadded:: 2015.8.0 + """ +- query = 'DROP TABLESPACE "{}"'.format(name) ++ query = f'DROP TABLESPACE "{name}"' + ret = _psql_prepare_and_run( + ["-c", query], + user=user, +@@ -1158,11 +1154,11 @@ def _add_role_flag(string, test, flag, cond=None, prefix="NO", addtxt="", skip=F + cond = test + if test is not None: + if cond: +- string = "{} {}".format(string, flag) ++ string = f"{string} {flag}" + else: +- string = "{0} {2}{1}".format(string, flag, prefix) ++ string = f"{string} {prefix}{flag}" + if addtxt: +- string = "{} {}".format(string, addtxt) ++ string = f"{string} {addtxt}" + return string + + +@@ -1224,7 +1220,7 @@ def _verify_password(role, password, verifier, method): + def _md5_password(role, password): + return "md5{}".format( + hashlib.md5( # nosec +- salt.utils.stringutils.to_bytes("{}{}".format(password, role)) ++ salt.utils.stringutils.to_bytes(f"{password}{role}") + ).hexdigest() + ) + +@@ -1343,7 +1339,7 @@ def _role_cmd_args( + if isinstance(groups, list): + groups = ",".join(groups) + for group in groups.split(","): +- sub_cmd = '{}; GRANT "{}" TO "{}"'.format(sub_cmd, group, name) ++ sub_cmd = f'{sub_cmd}; GRANT "{group}" TO "{name}"' + return sub_cmd + + +@@ -1380,7 +1376,7 @@ def _role_create( + log.info("%s '%s' already exists", typ_.capitalize(), name) + return False + +- sub_cmd = 'CREATE ROLE "{}" WITH'.format(name) ++ sub_cmd = f'CREATE ROLE "{name}" WITH' + sub_cmd = "{} {}".format( + sub_cmd, + _role_cmd_args( +@@ -1506,7 +1502,7 @@ def _role_update( + log.info("%s '%s' could not be found", typ_.capitalize(), name) + return False + +- sub_cmd = 'ALTER ROLE "{}" WITH'.format(name) ++ sub_cmd = f'ALTER ROLE "{name}" WITH' + sub_cmd = "{} {}".format( + sub_cmd, + _role_cmd_args( +@@ -1613,7 +1609,7 @@ def _role_remove( + return False + + # user exists, proceed +- sub_cmd = 'DROP ROLE "{}"'.format(name) ++ sub_cmd = f'DROP ROLE "{name}"' + _psql_prepare_and_run( + ["-c", sub_cmd], + runas=runas, +@@ -1995,14 +1991,14 @@ def create_extension( + args = ["CREATE EXTENSION"] + if if_not_exists: + args.append("IF NOT EXISTS") +- args.append('"{}"'.format(name)) ++ args.append(f'"{name}"') + sargs = [] + if schema: +- sargs.append('SCHEMA "{}"'.format(schema)) ++ sargs.append(f'SCHEMA "{schema}"') + if ext_version: +- sargs.append("VERSION {}".format(ext_version)) ++ sargs.append(f"VERSION {ext_version}") + if from_version: +- sargs.append("FROM {}".format(from_version)) ++ sargs.append(f"FROM {from_version}") + if sargs: + args.append("WITH") + args.extend(sargs) +@@ -2011,13 +2007,9 @@ def create_extension( + else: + args = [] + if schema and _EXTENSION_TO_MOVE in mtdata: +- args.append( +- 'ALTER EXTENSION "{}" SET SCHEMA "{}";'.format(name, schema) +- ) ++ args.append(f'ALTER EXTENSION "{name}" SET SCHEMA "{schema}";') + if ext_version and _EXTENSION_TO_UPGRADE in mtdata: +- args.append( +- 'ALTER EXTENSION "{}" UPDATE TO {};'.format(name, ext_version) +- ) ++ args.append(f'ALTER EXTENSION "{name}" UPDATE TO {ext_version};') + cmd = " ".join(args).strip() + if cmd: + _psql_prepare_and_run( +@@ -2227,7 +2219,7 @@ def owner_to( + + sqlfile = tempfile.NamedTemporaryFile() + sqlfile.write("begin;\n") +- sqlfile.write('alter database "{}" owner to "{}";\n'.format(dbname, ownername)) ++ sqlfile.write(f'alter database "{dbname}" owner to "{ownername}";\n') + + queries = ( + # schemas +@@ -2335,9 +2327,9 @@ def schema_create( + log.info("'%s' already exists in '%s'", name, dbname) + return False + +- sub_cmd = 'CREATE SCHEMA "{}"'.format(name) ++ sub_cmd = f'CREATE SCHEMA "{name}"' + if owner is not None: +- sub_cmd = '{} AUTHORIZATION "{}"'.format(sub_cmd, owner) ++ sub_cmd = f'{sub_cmd} AUTHORIZATION "{owner}"' + + ret = _psql_prepare_and_run( + ["-c", sub_cmd], +@@ -2401,7 +2393,7 @@ def schema_remove( + return False + + # schema exists, proceed +- sub_cmd = 'DROP SCHEMA "{}"'.format(name) ++ sub_cmd = f'DROP SCHEMA "{name}"' + _psql_prepare_and_run( + ["-c", sub_cmd], + runas=user, +@@ -2721,7 +2713,7 @@ def language_create( + log.info("Language %s already exists in %s", name, maintenance_db) + return False + +- query = "CREATE LANGUAGE {}".format(name) ++ query = f"CREATE LANGUAGE {name}" + + ret = _psql_prepare_and_run( + ["-c", query], +@@ -2776,7 +2768,7 @@ def language_remove( + log.info("Language %s does not exist in %s", name, maintenance_db) + return False + +- query = "DROP LANGUAGE {}".format(name) ++ query = f"DROP LANGUAGE {name}" + + ret = _psql_prepare_and_run( + ["-c", query], +@@ -3035,9 +3027,7 @@ def _validate_privileges(object_type, privs, privileges): + _perms.append("ALL") + + if object_type not in _PRIVILEGES_OBJECTS: +- raise SaltInvocationError( +- "Invalid object_type: {} provided".format(object_type) +- ) ++ raise SaltInvocationError(f"Invalid object_type: {object_type} provided") + + if not set(privs).issubset(set(_perms)): + raise SaltInvocationError( +@@ -3145,9 +3135,7 @@ def privileges_list( + query = _make_privileges_list_query(name, object_type, prepend) + + if object_type not in _PRIVILEGES_OBJECTS: +- raise SaltInvocationError( +- "Invalid object_type: {} provided".format(object_type) +- ) ++ raise SaltInvocationError(f"Invalid object_type: {object_type} provided") + + rows = psql_query( + query, +@@ -3439,15 +3427,15 @@ def privileges_grant( + _grants = ",".join(_privs) + + if object_type in ["table", "sequence"]: +- on_part = '{}."{}"'.format(prepend, object_name) ++ on_part = f'{prepend}."{object_name}"' + elif object_type == "function": +- on_part = "{}".format(object_name) ++ on_part = f"{object_name}" + else: +- on_part = '"{}"'.format(object_name) ++ on_part = f'"{object_name}"' + + if grant_option: + if object_type == "group": +- query = 'GRANT {} TO "{}" WITH ADMIN OPTION'.format(object_name, name) ++ query = f'GRANT {object_name} TO "{name}" WITH ADMIN OPTION' + elif object_type in ("table", "sequence") and object_name.upper() == "ALL": + query = 'GRANT {} ON ALL {}S IN SCHEMA {} TO "{}" WITH GRANT OPTION'.format( + _grants, object_type.upper(), prepend, name +@@ -3458,7 +3446,7 @@ def privileges_grant( + ) + else: + if object_type == "group": +- query = 'GRANT {} TO "{}"'.format(object_name, name) ++ query = f'GRANT {object_name} TO "{name}"' + elif object_type in ("table", "sequence") and object_name.upper() == "ALL": + query = 'GRANT {} ON ALL {}S IN SCHEMA {} TO "{}"'.format( + _grants, object_type.upper(), prepend, name +@@ -3587,12 +3575,12 @@ def privileges_revoke( + _grants = ",".join(_privs) + + if object_type in ["table", "sequence"]: +- on_part = "{}.{}".format(prepend, object_name) ++ on_part = f"{prepend}.{object_name}" + else: + on_part = object_name + + if object_type == "group": +- query = "REVOKE {} FROM {}".format(object_name, name) ++ query = f"REVOKE {object_name} FROM {name}" + else: + query = "REVOKE {} ON {} {} FROM {}".format( + _grants, object_type.upper(), on_part, name +diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py +index 841811dcdf..a084313059 100644 +--- a/salt/utils/cloud.py ++++ b/salt/utils/cloud.py +@@ -10,8 +10,8 @@ import hashlib + import logging + import multiprocessing + import os +-import pipes + import re ++import shlex + import shutil + import socket + import stat +@@ -199,7 +199,7 @@ def __ssh_gateway_arguments(kwargs): + "-oUserKnownHostsFile=/dev/null", + "-oControlPath=none", + str(ssh_gateway_key), +- "{}@{}".format(ssh_gateway_user, ssh_gateway), ++ f"{ssh_gateway_user}@{ssh_gateway}", + "-p", + str(ssh_gateway_port), + str(ssh_gateway_command), +@@ -228,18 +228,18 @@ def os_script(os_, vm_=None, opts=None, minion=""): + # The user provided an absolute path to the deploy script, let's use it + return __render_script(os_, vm_, opts, minion) + +- if os.path.isabs("{}.sh".format(os_)): ++ if os.path.isabs(f"{os_}.sh"): + # The user provided an absolute path to the deploy script, although no + # extension was provided. Let's use it anyway. +- return __render_script("{}.sh".format(os_), vm_, opts, minion) ++ return __render_script(f"{os_}.sh", vm_, opts, minion) + + for search_path in opts["deploy_scripts_search_path"]: + if os.path.isfile(os.path.join(search_path, os_)): + return __render_script(os.path.join(search_path, os_), vm_, opts, minion) + +- if os.path.isfile(os.path.join(search_path, "{}.sh".format(os_))): ++ if os.path.isfile(os.path.join(search_path, f"{os_}.sh")): + return __render_script( +- os.path.join(search_path, "{}.sh".format(os_)), vm_, opts, minion ++ os.path.join(search_path, f"{os_}.sh"), vm_, opts, minion + ) + # No deploy script was found, return an empty string + return "" +@@ -416,7 +416,7 @@ def bootstrap(vm_, opts=None): + ) + if key_filename is not None and not os.path.isfile(key_filename): + raise SaltCloudConfigError( +- "The defined ssh_keyfile '{}' does not exist".format(key_filename) ++ f"The defined ssh_keyfile '{key_filename}' does not exist" + ) + has_ssh_agent = False + if ( +@@ -782,8 +782,8 @@ def wait_for_port( + # Don't add new hosts to the host key database + "-oStrictHostKeyChecking=no", + # make sure ssh can time out on connection lose +- "-oServerAliveInterval={}".format(server_alive_interval), +- "-oServerAliveCountMax={}".format(server_alive_count_max), ++ f"-oServerAliveInterval={server_alive_interval}", ++ f"-oServerAliveCountMax={server_alive_count_max}", + # Set hosts key database path to /dev/null, i.e., non-existing + "-oUserKnownHostsFile=/dev/null", + # Don't re-use the SSH connection. Less failures. +@@ -808,21 +808,21 @@ def wait_for_port( + ] + ) + # Netcat command testing remote port +- command = "nc -z -w5 -q0 {} {}".format(host, port) ++ command = f"nc -z -w5 -q0 {host} {port}" + # SSH command + pcmd = "ssh {} {}@{} -p {} {}".format( + " ".join(ssh_args), + gateway["ssh_gateway_user"], + ssh_gateway, + ssh_gateway_port, +- pipes.quote("date"), ++ shlex.quote("date"), + ) + cmd = "ssh {} {}@{} -p {} {}".format( + " ".join(ssh_args), + gateway["ssh_gateway_user"], + ssh_gateway, + ssh_gateway_port, +- pipes.quote(command), ++ shlex.quote(command), + ) + log.debug("SSH command: '%s'", cmd) + +@@ -893,7 +893,7 @@ class Client: + service_name=None, + ): + self.service_name = service_name +- self._exe_file = "{}.exe".format(self.service_name) ++ self._exe_file = f"{self.service_name}.exe" + self._client = PsExecClient(server, username, password, port, encrypt) + self._client._service = ScmrService(self.service_name, self._client.session) + +@@ -943,7 +943,7 @@ class Client: + # delete the PAExec executable + smb_tree = TreeConnect( + self._client.session, +- r"\\{}\ADMIN$".format(self._client.connection.server_name), ++ rf"\\{self._client.connection.server_name}\ADMIN$", + ) + log.info("Connecting to SMB Tree %s", smb_tree.share_name) + smb_tree.connect() +@@ -968,10 +968,10 @@ def run_winexe_command(cmd, args, host, username, password, port=445): + """ + Run a command remotely via the winexe executable + """ +- creds = "-U '{}%{}' //{}".format(username, password, host) +- logging_creds = "-U '{}%XXX-REDACTED-XXX' //{}".format(username, host) +- cmd = "winexe {} {} {}".format(creds, cmd, args) +- logging_cmd = "winexe {} {} {}".format(logging_creds, cmd, args) ++ creds = f"-U '{username}%{password}' //{host}" ++ logging_creds = f"-U '{username}%XXX-REDACTED-XXX' //{host}" ++ cmd = f"winexe {creds} {cmd} {args}" ++ logging_cmd = f"winexe {logging_creds} {cmd} {args}" + return win_cmd(cmd, logging_command=logging_cmd) + + +@@ -979,7 +979,7 @@ def run_psexec_command(cmd, args, host, username, password, port=445): + """ + Run a command remotely using the psexec protocol + """ +- service_name = "PS-Exec-{}".format(uuid.uuid4()) ++ service_name = f"PS-Exec-{uuid.uuid4()}" + with Client( + host, username, password, port=port, encrypt=False, service_name=service_name + ) as client: +@@ -1098,7 +1098,7 @@ def validate_windows_cred_winexe( + """ + Check if the windows credentials are valid + """ +- cmd = "winexe -U '{}%{}' //{} \"hostname\"".format(username, password, host) ++ cmd = f"winexe -U '{username}%{password}' //{host} \"hostname\"" + logging_cmd = "winexe -U '{}%XXX-REDACTED-XXX' //{} \"hostname\"".format( + username, host + ) +@@ -1240,7 +1240,7 @@ def deploy_windows( + winrm_port=5986, + winrm_use_ssl=True, + winrm_verify_ssl=True, +- **kwargs ++ **kwargs, + ): + """ + Copy the install files to a remote Windows box, and execute them +@@ -1299,20 +1299,20 @@ def deploy_windows( + + salt.utils.smb.mkdirs("salttemp", conn=smb_conn) + root_dir = "ProgramData/Salt Project/Salt" +- salt.utils.smb.mkdirs("{}/conf/pki/minion".format(root_dir), conn=smb_conn) ++ salt.utils.smb.mkdirs(f"{root_dir}/conf/pki/minion", conn=smb_conn) + root_dir = "ProgramData\\Salt Project\\Salt" + + if minion_pub: + salt.utils.smb.put_str( + minion_pub, +- "{}\\conf\\pki\\minion\\minion.pub".format(root_dir), ++ f"{root_dir}\\conf\\pki\\minion\\minion.pub", + conn=smb_conn, + ) + + if minion_pem: + salt.utils.smb.put_str( + minion_pem, +- "{}\\conf\\pki\\minion\\minion.pem".format(root_dir), ++ f"{root_dir}\\conf\\pki\\minion\\minion.pem", + conn=smb_conn, + ) + +@@ -1324,7 +1324,7 @@ def deploy_windows( + try: + salt.utils.smb.put_file( + master_sign_pub_file, +- "{}\\conf\\pki\\minion\\master_sign.pub".format(root_dir), ++ f"{root_dir}\\conf\\pki\\minion\\master_sign.pub", + conn=smb_conn, + ) + except Exception as e: # pylint: disable=broad-except +@@ -1342,16 +1342,16 @@ def deploy_windows( + installer = comps[-1] + salt.utils.smb.put_file( + win_installer, +- "salttemp\\{}".format(installer), ++ f"salttemp\\{installer}", + "C$", + conn=smb_conn, + ) + +- cmd = "c:\\salttemp\\{}".format(installer) ++ cmd = f"c:\\salttemp\\{installer}" + args = [ + "/S", +- "/master={}".format(_format_master_param(master)), +- "/minion-name={}".format(name), ++ f"/master={_format_master_param(master)}", ++ f"/minion-name={name}", + ] + + if use_winrm: +@@ -1362,7 +1362,7 @@ def deploy_windows( + ) + + if ret_code != 0: +- raise Exception("Fail installer {}".format(ret_code)) ++ raise Exception(f"Fail installer {ret_code}") + + # Copy over minion_conf + if minion_conf: +@@ -1378,7 +1378,7 @@ def deploy_windows( + if minion_grains: + salt.utils.smb.put_str( + salt_config_to_yaml(minion_grains, line_break="\r\n"), +- "{}\\conf\\grains".format(root_dir), ++ f"{root_dir}\\conf\\grains", + conn=smb_conn, + ) + # Add special windows minion configuration +@@ -1395,7 +1395,7 @@ def deploy_windows( + minion_conf = dict(minion_conf, **windows_minion_conf) + salt.utils.smb.put_str( + salt_config_to_yaml(minion_conf, line_break="\r\n"), +- "{}\\conf\\minion".format(root_dir), ++ f"{root_dir}\\conf\\minion", + conn=smb_conn, + ) + # Delete C:\salttmp\ and installer file +@@ -1405,7 +1405,7 @@ def deploy_windows( + winrm_cmd(winrm_session, "rmdir", ["/Q", "/S", "C:\\salttemp\\"]) + else: + salt.utils.smb.delete_file( +- "salttemp\\{}".format(installer), "C$", conn=smb_conn ++ f"salttemp\\{installer}", "C$", conn=smb_conn + ) + salt.utils.smb.delete_directory("salttemp", "C$", conn=smb_conn) + # Shell out to psexec to ensure salt-minion service started +@@ -1429,8 +1429,8 @@ def deploy_windows( + # Fire deploy action + fire_event( + "event", +- "{} has been deployed at {}".format(name, host), +- "salt/cloud/{}/deploy_windows".format(name), ++ f"{name} has been deployed at {host}", ++ f"salt/cloud/{name}/deploy_windows", + args={"name": name}, + sock_dir=opts.get("sock_dir", os.path.join(__opts__["sock_dir"], "master")), + transport=opts.get("transport", "zeromq"), +@@ -1480,7 +1480,7 @@ def deploy_script( + master_sign_pub_file=None, + cloud_grains=None, + force_minion_config=False, +- **kwargs ++ **kwargs, + ): + """ + Copy a deploy script to a remote server, execute it, and remove it +@@ -1496,7 +1496,7 @@ def deploy_script( + ) + 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" + ) + + gateway = None +@@ -1543,35 +1543,28 @@ def deploy_script( + ssh_kwargs["password"] = password + + if root_cmd( +- "test -e '{}'".format(tmp_dir), +- tty, +- sudo, +- allow_failure=True, +- **ssh_kwargs ++ f"test -e '{tmp_dir}'", tty, sudo, allow_failure=True, **ssh_kwargs + ): + ret = root_cmd( +- "sh -c \"( mkdir -p -m 700 '{}' )\"".format(tmp_dir), ++ f"sh -c \"( mkdir -p -m 700 '{tmp_dir}' )\"", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + if ret: + raise SaltCloudSystemExit( +- "Can't create temporary directory in {} !".format(tmp_dir) ++ f"Can't create temporary directory in {tmp_dir} !" + ) + if sudo: + comps = tmp_dir.lstrip("/").rstrip("/").split("/") + if comps: + if len(comps) > 1 or comps[0] != "tmp": + ret = root_cmd( +- 'chown {} "{}"'.format(username, tmp_dir), +- tty, +- sudo, +- **ssh_kwargs ++ f'chown {username} "{tmp_dir}"', tty, sudo, **ssh_kwargs + ) + if ret: + raise SaltCloudSystemExit( +- "Cant set {} ownership on {}".format(username, tmp_dir) ++ f"Cant set {username} ownership on {tmp_dir}" + ) + + if not isinstance(file_map, dict): +@@ -1601,15 +1594,13 @@ def deploy_script( + remote_dir = os.path.dirname(remote_file) + + if remote_dir not in remote_dirs: +- root_cmd( +- "mkdir -p '{}'".format(remote_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"mkdir -p '{remote_dir}'", tty, sudo, **ssh_kwargs) + if ssh_kwargs["username"] != "root": + root_cmd( + "chown {} '{}'".format(ssh_kwargs["username"], remote_dir), + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + remote_dirs.append(remote_dir) + ssh_file(opts, remote_file, kwargs=ssh_kwargs, local_file=local_file) +@@ -1617,21 +1608,21 @@ def deploy_script( + + # Minion configuration + if minion_pem: +- ssh_file(opts, "{}/minion.pem".format(tmp_dir), minion_pem, ssh_kwargs) ++ ssh_file(opts, f"{tmp_dir}/minion.pem", minion_pem, ssh_kwargs) + ret = root_cmd( +- "chmod 600 '{}/minion.pem'".format(tmp_dir), tty, sudo, **ssh_kwargs ++ f"chmod 600 '{tmp_dir}/minion.pem'", tty, sudo, **ssh_kwargs + ) + if ret: + raise SaltCloudSystemExit( +- "Can't set perms on {}/minion.pem".format(tmp_dir) ++ f"Can't set perms on {tmp_dir}/minion.pem" + ) + if minion_pub: +- ssh_file(opts, "{}/minion.pub".format(tmp_dir), minion_pub, ssh_kwargs) ++ ssh_file(opts, f"{tmp_dir}/minion.pub", minion_pub, ssh_kwargs) + + if master_sign_pub_file: + ssh_file( + opts, +- "{}/master_sign.pub".format(tmp_dir), ++ f"{tmp_dir}/master_sign.pub", + kwargs=ssh_kwargs, + local_file=master_sign_pub_file, + ) +@@ -1649,7 +1640,7 @@ def deploy_script( + if minion_grains: + ssh_file( + opts, +- "{}/grains".format(tmp_dir), ++ f"{tmp_dir}/grains", + salt_config_to_yaml(minion_grains), + ssh_kwargs, + ) +@@ -1657,24 +1648,22 @@ def deploy_script( + minion_conf["grains"] = {"salt-cloud": cloud_grains} + ssh_file( + opts, +- "{}/minion".format(tmp_dir), ++ f"{tmp_dir}/minion", + salt_config_to_yaml(minion_conf), + ssh_kwargs, + ) + + # Master configuration + if master_pem: +- ssh_file(opts, "{}/master.pem".format(tmp_dir), master_pem, ssh_kwargs) ++ ssh_file(opts, f"{tmp_dir}/master.pem", master_pem, ssh_kwargs) + ret = root_cmd( +- "chmod 600 '{}/master.pem'".format(tmp_dir), tty, sudo, **ssh_kwargs ++ f"chmod 600 '{tmp_dir}/master.pem'", tty, sudo, **ssh_kwargs + ) + if ret: +- raise SaltCloudSystemExit( +- "Cant set perms on {}/master.pem".format(tmp_dir) +- ) ++ raise SaltCloudSystemExit(f"Cant set perms on {tmp_dir}/master.pem") + + if master_pub: +- ssh_file(opts, "{}/master.pub".format(tmp_dir), master_pub, ssh_kwargs) ++ ssh_file(opts, f"{tmp_dir}/master.pub", master_pub, ssh_kwargs) + + if master_conf: + if not isinstance(master_conf, dict): +@@ -1688,34 +1677,31 @@ def deploy_script( + + ssh_file( + opts, +- "{}/master".format(tmp_dir), ++ f"{tmp_dir}/master", + salt_config_to_yaml(master_conf), + ssh_kwargs, + ) + + # XXX: We need to make these paths configurable +- preseed_minion_keys_tempdir = "{}/preseed-minion-keys".format(tmp_dir) ++ preseed_minion_keys_tempdir = f"{tmp_dir}/preseed-minion-keys" + if preseed_minion_keys is not None: + # Create remote temp dir + ret = root_cmd( +- "mkdir '{}'".format(preseed_minion_keys_tempdir), +- tty, +- sudo, +- **ssh_kwargs ++ f"mkdir '{preseed_minion_keys_tempdir}'", tty, sudo, **ssh_kwargs + ) + if ret: + raise SaltCloudSystemExit( +- "Cant create {}".format(preseed_minion_keys_tempdir) ++ f"Cant create {preseed_minion_keys_tempdir}" + ) + ret = root_cmd( +- "chmod 700 '{}'".format(preseed_minion_keys_tempdir), ++ f"chmod 700 '{preseed_minion_keys_tempdir}'", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + if ret: + raise SaltCloudSystemExit( +- "Can't set perms on {}".format(preseed_minion_keys_tempdir) ++ f"Can't set perms on {preseed_minion_keys_tempdir}" + ) + if ssh_kwargs["username"] != "root": + root_cmd( +@@ -1724,7 +1710,7 @@ def deploy_script( + ), + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + + # Copy pre-seed minion keys +@@ -1734,10 +1720,10 @@ def deploy_script( + + if ssh_kwargs["username"] != "root": + root_cmd( +- "chown -R root '{}'".format(preseed_minion_keys_tempdir), ++ f"chown -R root '{preseed_minion_keys_tempdir}'", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + if ret: + raise SaltCloudSystemExit( +@@ -1751,25 +1737,21 @@ def deploy_script( + for command in preflight_cmds: + cmd_ret = root_cmd(command, tty, sudo, **ssh_kwargs) + if cmd_ret: +- raise SaltCloudSystemExit( +- "Pre-flight command failed: '{}'".format(command) +- ) ++ raise SaltCloudSystemExit(f"Pre-flight command failed: '{command}'") + + # The actual deploy script + if script: + # got strange escaping issues with sudoer, going onto a + # subshell fixes that +- ssh_file(opts, "{}/deploy.sh".format(tmp_dir), script, ssh_kwargs) ++ ssh_file(opts, f"{tmp_dir}/deploy.sh", script, ssh_kwargs) + ret = root_cmd( +- "sh -c \"( chmod +x '{}/deploy.sh' )\";exit $?".format(tmp_dir), ++ f"sh -c \"( chmod +x '{tmp_dir}/deploy.sh' )\";exit $?", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + if ret: +- raise SaltCloudSystemExit( +- "Can't set perms on {}/deploy.sh".format(tmp_dir) +- ) ++ raise SaltCloudSystemExit(f"Can't set perms on {tmp_dir}/deploy.sh") + + time_used = time.mktime(time.localtime()) - time.mktime(starttime) + newtimeout = timeout - time_used +@@ -1785,7 +1767,7 @@ def deploy_script( + kwargs=dict( + name=name, sock_dir=sock_dir, timeout=newtimeout, queue=queue + ), +- name="DeployScriptCheckAuth({})".format(name), ++ name=f"DeployScriptCheckAuth({name})", + ) + log.debug("Starting new process to wait for salt-minion") + process.start() +@@ -1793,7 +1775,7 @@ def deploy_script( + # Run the deploy script + if script: + if "bootstrap-salt" in script: +- deploy_command += " -c '{}'".format(tmp_dir) ++ deploy_command += f" -c '{tmp_dir}'" + if force_minion_config: + deploy_command += " -F" + if make_syndic is True: +@@ -1805,9 +1787,9 @@ def deploy_script( + if keep_tmp is True: + deploy_command += " -K" + if preseed_minion_keys is not None: +- deploy_command += " -k '{}'".format(preseed_minion_keys_tempdir) ++ deploy_command += f" -k '{preseed_minion_keys_tempdir}'" + if script_args: +- deploy_command += " {}".format(script_args) ++ deploy_command += f" {script_args}" + + if script_env: + if not isinstance(script_env, dict): +@@ -1826,15 +1808,15 @@ def deploy_script( + # Upload our environ setter wrapper + ssh_file( + opts, +- "{}/environ-deploy-wrapper.sh".format(tmp_dir), ++ f"{tmp_dir}/environ-deploy-wrapper.sh", + "\n".join(environ_script_contents), + ssh_kwargs, + ) + root_cmd( +- "chmod +x '{}/environ-deploy-wrapper.sh'".format(tmp_dir), ++ f"chmod +x '{tmp_dir}/environ-deploy-wrapper.sh'", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + # The deploy command is now our wrapper + deploy_command = "'{}/environ-deploy-wrapper.sh'".format( +@@ -1842,22 +1824,20 @@ def deploy_script( + ) + if root_cmd(deploy_command, tty, sudo, **ssh_kwargs) != 0: + raise SaltCloudSystemExit( +- "Executing the command '{}' failed".format(deploy_command) ++ f"Executing the command '{deploy_command}' failed" + ) + log.debug("Executed command '%s'", deploy_command) + + # Remove the deploy script + if not keep_tmp: +- root_cmd( +- "rm -f '{}/deploy.sh'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/deploy.sh'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/deploy.sh", tmp_dir) + if script_env: + root_cmd( +- "rm -f '{}/environ-deploy-wrapper.sh'".format(tmp_dir), ++ f"rm -f '{tmp_dir}/environ-deploy-wrapper.sh'", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + log.debug("Removed %s/environ-deploy-wrapper.sh", tmp_dir) + +@@ -1866,57 +1846,40 @@ def deploy_script( + else: + # Remove minion configuration + if minion_pub: +- root_cmd( +- "rm -f '{}/minion.pub'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/minion.pub'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/minion.pub", tmp_dir) + if minion_pem: +- root_cmd( +- "rm -f '{}/minion.pem'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/minion.pem'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/minion.pem", tmp_dir) + if minion_conf: +- root_cmd( +- "rm -f '{}/grains'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/grains'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/grains", tmp_dir) +- root_cmd( +- "rm -f '{}/minion'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/minion'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/minion", tmp_dir) + if master_sign_pub_file: + root_cmd( +- "rm -f {}/master_sign.pub".format(tmp_dir), +- tty, +- sudo, +- **ssh_kwargs ++ f"rm -f {tmp_dir}/master_sign.pub", tty, sudo, **ssh_kwargs + ) + log.debug("Removed %s/master_sign.pub", tmp_dir) + + # Remove master configuration + if master_pub: +- root_cmd( +- "rm -f '{}/master.pub'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/master.pub'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/master.pub", tmp_dir) + if master_pem: +- root_cmd( +- "rm -f '{}/master.pem'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/master.pem'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/master.pem", tmp_dir) + if master_conf: +- root_cmd( +- "rm -f '{}/master'".format(tmp_dir), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"rm -f '{tmp_dir}/master'", tty, sudo, **ssh_kwargs) + log.debug("Removed %s/master", tmp_dir) + + # Remove pre-seed keys directory + if preseed_minion_keys is not None: + root_cmd( +- "rm -rf '{}'".format(preseed_minion_keys_tempdir), ++ f"rm -rf '{preseed_minion_keys_tempdir}'", + tty, + sudo, +- **ssh_kwargs ++ **ssh_kwargs, + ) + log.debug("Removed %s", preseed_minion_keys_tempdir) + +@@ -1931,15 +1894,13 @@ def deploy_script( + # for line in output: + # print(line) + log.info("Executing %s on the salt-minion", start_action) +- root_cmd( +- "salt-call {}".format(start_action), tty, sudo, **ssh_kwargs +- ) ++ root_cmd(f"salt-call {start_action}", tty, sudo, **ssh_kwargs) + log.info("Finished executing %s on the salt-minion", start_action) + # Fire deploy action + fire_event( + "event", +- "{} has been deployed at {}".format(name, host), +- "salt/cloud/{}/deploy_script".format(name), ++ f"{name} has been deployed at {host}", ++ f"salt/cloud/{name}/deploy_script", + args={"name": name, "host": host}, + sock_dir=opts.get( + "sock_dir", os.path.join(__opts__["sock_dir"], "master") +@@ -1972,7 +1933,7 @@ def run_inline_script( + tty=None, + opts=None, + tmp_dir="/tmp/.saltcloud-inline_script", +- **kwargs ++ **kwargs, + ): + """ + Run the inline script commands, one by one +@@ -2029,11 +1990,11 @@ def run_inline_script( + # TODO: check edge cases (e.g. ssh gateways, salt deploy disabled, etc.) + if ( + root_cmd( +- 'test -e \\"{}\\"'.format(tmp_dir), ++ f'test -e \\"{tmp_dir}\\"', + tty, + sudo, + allow_failure=True, +- **ssh_kwargs ++ **ssh_kwargs, + ) + and inline_script + ): +@@ -2041,11 +2002,11 @@ def run_inline_script( + for cmd_line in inline_script: + log.info("Executing inline command: %s", cmd_line) + ret = root_cmd( +- 'sh -c "( {} )"'.format(cmd_line), ++ f'sh -c "( {cmd_line} )"', + tty, + sudo, + allow_failure=True, +- **ssh_kwargs ++ **ssh_kwargs, + ) + if ret: + log.info("[%s] Output: %s", cmd_line, ret) +@@ -2149,7 +2110,7 @@ def _exec_ssh_cmd(cmd, error_msg=None, allow_failure=False, **kwargs): + time.sleep(0.5) + if proc.exitstatus != 0 and allow_failure is False: + raise SaltCloudSystemExit( +- "Command '{}' failed. Exit code: {}".format(cmd, proc.exitstatus) ++ f"Command '{cmd}' failed. Exit code: {proc.exitstatus}" + ) + return proc.exitstatus + except salt.utils.vt.TerminalException as err: +@@ -2252,7 +2213,7 @@ def scp_file(dest_path, contents=None, kwargs=None, local_file=None): + cmd, + error_msg="Failed to upload file '{0}': {1}\n{2}", + password_retries=3, +- **kwargs ++ **kwargs, + ) + finally: + if contents is not None: +@@ -2370,7 +2331,7 @@ def sftp_file(dest_path, contents=None, kwargs=None, local_file=None): + cmd, + error_msg="Failed to upload file '{0}': {1}\n{2}", + password_retries=3, +- **kwargs ++ **kwargs, + ) + finally: + if contents is not None: +@@ -2430,11 +2391,11 @@ def root_cmd(command, tty, sudo, allow_failure=False, **kwargs): + + if sudo: + if sudo_password is None: +- command = "sudo {}".format(command) ++ command = f"sudo {command}" + logging_command = command + else: +- logging_command = 'sudo -S "XXX-REDACTED-XXX" {}'.format(command) +- command = "sudo -S {}".format(command) ++ logging_command = f'sudo -S "XXX-REDACTED-XXX" {command}' ++ command = f"sudo -S {command}" + + log.debug("Using sudo to run command %s", logging_command) + +@@ -2453,9 +2414,9 @@ def root_cmd(command, tty, sudo, allow_failure=False, **kwargs): + ssh_args.extend( + [ + # Don't add new hosts to the host key database +- "-oStrictHostKeyChecking={}".format(host_key_checking), ++ f"-oStrictHostKeyChecking={host_key_checking}", + # Set hosts key database path to /dev/null, i.e., non-existing +- "-oUserKnownHostsFile={}".format(known_hosts_file), ++ f"-oUserKnownHostsFile={known_hosts_file}", + # Don't re-use the SSH connection. Less failures. + "-oControlPath=none", + ] +@@ -2488,12 +2449,12 @@ def root_cmd(command, tty, sudo, allow_failure=False, **kwargs): + + cmd = "ssh {0} {1[username]}@{1[hostname]} ".format(" ".join(ssh_args), kwargs) + logging_command = cmd + logging_command +- cmd = cmd + pipes.quote(command) ++ cmd = cmd + shlex.quote(command) + + hard_timeout = kwargs.get("hard_timeout") + if hard_timeout is not None: +- logging_command = "timeout {} {}".format(hard_timeout, logging_command) +- cmd = "timeout {} {}".format(hard_timeout, cmd) ++ logging_command = f"timeout {hard_timeout} {logging_command}" ++ cmd = f"timeout {hard_timeout} {cmd}" + + log.debug("SSH command: '%s'", logging_command) + +@@ -2515,7 +2476,7 @@ def check_auth(name, sock_dir=None, queue=None, timeout=300): + ret = event.get_event(full=True) + if ret is None: + continue +- if ret["tag"] == "salt/minion/{}/start".format(name): ++ if ret["tag"] == f"salt/minion/{name}/start": + queue.put(name) + newtimeout = 0 + log.debug("Minion %s is ready to receive commands", name) +@@ -2561,7 +2522,7 @@ def check_name(name, safe_chars): + """ + Check whether the specified name contains invalid characters + """ +- regexp = re.compile("[^{}]".format(safe_chars)) ++ regexp = re.compile(f"[^{safe_chars}]") + if regexp.search(name): + raise SaltCloudException( + "{} contains characters not supported by this cloud provider. " +@@ -2855,7 +2816,7 @@ def request_minion_cachedir( + "provider": provider, + } + +- fname = "{}.p".format(minion_id) ++ fname = f"{minion_id}.p" + path = os.path.join(base, "requested", fname) + with salt.utils.files.fopen(path, "wb") as fh_: + salt.utils.msgpack.dump(data, fh_, encoding=MSGPACK_ENCODING) +@@ -2886,7 +2847,7 @@ def change_minion_cachedir( + if base is None: + base = __opts__["cachedir"] + +- fname = "{}.p".format(minion_id) ++ fname = f"{minion_id}.p" + path = os.path.join(base, cachedir, fname) + + with salt.utils.files.fopen(path, "r") as fh_: +@@ -2909,7 +2870,7 @@ def activate_minion_cachedir(minion_id, base=None): + if base is None: + base = __opts__["cachedir"] + +- fname = "{}.p".format(minion_id) ++ fname = f"{minion_id}.p" + src = os.path.join(base, "requested", fname) + dst = os.path.join(base, "active") + shutil.move(src, dst) +@@ -2931,7 +2892,7 @@ def delete_minion_cachedir(minion_id, provider, opts, base=None): + base = __opts__["cachedir"] + + driver = next(iter(__opts__["providers"][provider].keys())) +- fname = "{}.p".format(minion_id) ++ fname = f"{minion_id}.p" + for cachedir in "requested", "active": + path = os.path.join(base, cachedir, driver, provider, fname) + log.debug("path: %s", path) +@@ -3024,7 +2985,7 @@ def update_bootstrap(config, url=None): + # in last case, assuming we got a script content + else: + script_content = url +- script_name = "{}.sh".format(hashlib.sha1(script_content).hexdigest()) ++ script_name = f"{hashlib.sha1(script_content).hexdigest()}.sh" + + if not script_content: + raise ValueError("No content in bootstrap script !") +@@ -3118,7 +3079,7 @@ def cache_node_list(nodes, provider, opts): + + for node in nodes: + diff_node_cache(prov_dir, node, nodes[node], opts) +- path = os.path.join(prov_dir, "{}.p".format(node)) ++ path = os.path.join(prov_dir, f"{node}.p") + with salt.utils.files.fopen(path, "wb") as fh_: + salt.utils.msgpack.dump(nodes[node], fh_, encoding=MSGPACK_ENCODING) + +@@ -3173,7 +3134,7 @@ def missing_node_cache(prov_dir, node_list, provider, opts): + fire_event( + "event", + "cached node missing from provider", +- "salt/cloud/{}/cache_node_missing".format(node), ++ f"salt/cloud/{node}/cache_node_missing", + args={"missing node": node}, + sock_dir=opts.get( + "sock_dir", os.path.join(__opts__["sock_dir"], "master") +@@ -3201,7 +3162,7 @@ def diff_node_cache(prov_dir, node, new_data, opts): + + if node is None: + return +- path = "{}.p".format(os.path.join(prov_dir, node)) ++ path = f"{os.path.join(prov_dir, node)}.p" + + if not os.path.exists(path): + event_data = _strip_cache_events(new_data, opts) +@@ -3209,7 +3170,7 @@ def diff_node_cache(prov_dir, node, new_data, opts): + fire_event( + "event", + "new node found", +- "salt/cloud/{}/cache_node_new".format(node), ++ f"salt/cloud/{node}/cache_node_new", + args={"new_data": event_data}, + sock_dir=opts.get("sock_dir", os.path.join(__opts__["sock_dir"], "master")), + transport=opts.get("transport", "zeromq"), +@@ -3233,7 +3194,7 @@ def diff_node_cache(prov_dir, node, new_data, opts): + fire_event( + "event", + "node data differs", +- "salt/cloud/{}/cache_node_diff".format(node), ++ f"salt/cloud/{node}/cache_node_diff", + args={ + "new_data": _strip_cache_events(new_data, opts), + "cache_data": _strip_cache_events(cache_data, opts), +@@ -3277,7 +3238,7 @@ def _salt_cloud_force_ascii(exc): + errors. + """ + if not isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)): +- raise TypeError("Can't handle {}".format(exc)) ++ raise TypeError(f"Can't handle {exc}") + + unicode_trans = { + # Convert non-breaking space to space +@@ -3337,7 +3298,7 @@ def store_password_in_keyring(credential_id, username, password=None): + + # pylint: enable=import-error + if password is None: +- prompt = "Please enter password for {}: ".format(credential_id) ++ prompt = f"Please enter password for {credential_id}: " + try: + password = getpass.getpass(prompt) + except EOFError: +diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py +index a6a8a27960..d90957a008 100644 +--- a/salt/utils/jinja.py ++++ b/salt/utils/jinja.py +@@ -2,13 +2,12 @@ + Jinja loading utils to enable a more powerful backend for jinja templates + """ + +- + import itertools + import logging + import os.path +-import pipes + import pprint + import re ++import shlex + import time + import uuid + import warnings +@@ -242,11 +241,11 @@ class PrintableDict(OrderedDict): + if isinstance(value, str): + # keeps quotes around strings + # pylint: disable=repr-flag-used-in-string +- output.append("{!r}: {!r}".format(key, value)) ++ output.append(f"{key!r}: {value!r}") + # pylint: enable=repr-flag-used-in-string + else: + # let default output +- output.append("{!r}: {!s}".format(key, value)) ++ output.append(f"{key!r}: {value!s}") + return "{" + ", ".join(output) + "}" + + def __repr__(self): # pylint: disable=W0221 +@@ -255,7 +254,7 @@ class PrintableDict(OrderedDict): + # Raw string formatter required here because this is a repr + # function. + # pylint: disable=repr-flag-used-in-string +- output.append("{!r}: {!r}".format(key, value)) ++ output.append(f"{key!r}: {value!r}") + # pylint: enable=repr-flag-used-in-string + return "{" + ", ".join(output) + "}" + +@@ -441,7 +440,7 @@ def quote(txt): + + 'my_text' + """ +- return pipes.quote(txt) ++ return shlex.quote(txt) + + + @jinja_filter() +@@ -1095,13 +1094,13 @@ class SerializerExtension(Extension): + # to the stringified version of the exception. + msg += str(exc) + else: +- msg += "{}\n".format(problem) ++ msg += f"{problem}\n" + msg += salt.utils.stringutils.get_context( + buf, line, marker=" <======================" + ) + raise TemplateRuntimeError(msg) + except AttributeError: +- raise TemplateRuntimeError("Unable to load yaml from {}".format(value)) ++ raise TemplateRuntimeError(f"Unable to load yaml from {value}") + + def load_json(self, value): + if isinstance(value, TemplateModule): +@@ -1109,7 +1108,7 @@ class SerializerExtension(Extension): + try: + return salt.utils.json.loads(value) + except (ValueError, TypeError, AttributeError): +- raise TemplateRuntimeError("Unable to load json from {}".format(value)) ++ raise TemplateRuntimeError(f"Unable to load json from {value}") + + def load_text(self, value): + if isinstance(value, TemplateModule): +@@ -1144,7 +1143,7 @@ class SerializerExtension(Extension): + return self._parse_profile_block(parser, label, "profile block", body, lineno) + + def _create_profile_id(self, parser): +- return "_salt_profile_{}".format(parser.free_identifier().name) ++ return f"_salt_profile_{parser.free_identifier().name}" + + def _profile_start(self, label, source): + return (label, source, time.time()) +@@ -1186,7 +1185,7 @@ class SerializerExtension(Extension): + filter_name = parser.stream.current.value + lineno = next(parser.stream).lineno + if filter_name not in self.environment.filters: +- parser.fail("Unable to parse {}".format(filter_name), lineno) ++ parser.fail(f"Unable to parse {filter_name}", lineno) + + parser.stream.expect("name:as") + target = parser.parse_assign_target() +@@ -1225,7 +1224,7 @@ class SerializerExtension(Extension): + nodes.Name(target, "store").set_lineno(lineno), + nodes.Filter( + nodes.Name(target, "load").set_lineno(lineno), +- "load_{}".format(converter), ++ f"load_{converter}", + [], + [], + None, +@@ -1234,7 +1233,7 @@ class SerializerExtension(Extension): + ).set_lineno(lineno), + ] + return self._parse_profile_block( +- parser, import_node.template, "import_{}".format(converter), body, lineno ++ parser, import_node.template, f"import_{converter}", body, lineno + ) + + def dict_to_sls_yaml_params(self, value, flow_style=False): +-- +2.39.2 + diff --git a/salt.spec.in b/salt.spec.in index 0637adc..339b2a0 100644 --- a/salt.spec.in +++ b/salt.spec.in @@ -40,6 +40,11 @@ Source20: %{name}-run.fish Source21: %{name}-syndic.fish Patch0: contextvars.patch +Patch1: 0001-Backport-locale.getdefaultlocale-into-Salt.-It-s-get.patch +Patch2: 0002-Hide-known-DeprecationWarning-related-to-PEP-594.patch +Patch3: 0003-Stop-using-the-deprecated-cgi-module.patch +Patch4: 0004-Fixed-committed-reviewer-suggestion.patch +Patch5: 0005-Stop-using-the-deprecated-pipes-module.patch BuildArch: noarch %ifarch %{ix86} x86_64