pyinfra 3.0b1__py2.py3-none-any.whl → 3.0b3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. pyinfra/api/arguments.py +9 -3
  2. pyinfra/api/arguments_typed.py +8 -5
  3. pyinfra/api/command.py +5 -3
  4. pyinfra/api/config.py +115 -13
  5. pyinfra/api/connectors.py +5 -2
  6. pyinfra/api/facts.py +33 -32
  7. pyinfra/api/host.py +5 -5
  8. pyinfra/api/inventory.py +4 -0
  9. pyinfra/api/operation.py +22 -14
  10. pyinfra/api/util.py +24 -16
  11. pyinfra/connectors/base.py +3 -6
  12. pyinfra/connectors/docker.py +2 -9
  13. pyinfra/connectors/local.py +2 -2
  14. pyinfra/connectors/ssh.py +2 -2
  15. pyinfra/connectors/util.py +6 -7
  16. pyinfra/connectors/vagrant.py +5 -5
  17. pyinfra/context.py +1 -0
  18. pyinfra/facts/apk.py +2 -0
  19. pyinfra/facts/apt.py +2 -0
  20. pyinfra/facts/brew.py +2 -0
  21. pyinfra/facts/bsdinit.py +2 -0
  22. pyinfra/facts/cargo.py +2 -0
  23. pyinfra/facts/choco.py +2 -0
  24. pyinfra/facts/deb.py +7 -2
  25. pyinfra/facts/dnf.py +2 -0
  26. pyinfra/facts/docker.py +18 -0
  27. pyinfra/facts/files.py +2 -0
  28. pyinfra/facts/gem.py +2 -0
  29. pyinfra/facts/gpg.py +2 -0
  30. pyinfra/facts/hardware.py +30 -22
  31. pyinfra/facts/launchd.py +2 -0
  32. pyinfra/facts/lxd.py +2 -0
  33. pyinfra/facts/mysql.py +12 -6
  34. pyinfra/facts/npm.py +1 -0
  35. pyinfra/facts/openrc.py +2 -0
  36. pyinfra/facts/pacman.py +6 -2
  37. pyinfra/facts/pip.py +2 -0
  38. pyinfra/facts/pkg.py +2 -0
  39. pyinfra/facts/pkgin.py +2 -0
  40. pyinfra/facts/postgres.py +6 -6
  41. pyinfra/facts/postgresql.py +2 -0
  42. pyinfra/facts/rpm.py +12 -9
  43. pyinfra/facts/runit.py +68 -0
  44. pyinfra/facts/server.py +10 -13
  45. pyinfra/facts/snap.py +2 -0
  46. pyinfra/facts/systemd.py +2 -0
  47. pyinfra/facts/upstart.py +2 -0
  48. pyinfra/facts/util/packaging.py +3 -2
  49. pyinfra/facts/vzctl.py +2 -0
  50. pyinfra/facts/xbps.py +2 -0
  51. pyinfra/facts/yum.py +2 -0
  52. pyinfra/facts/zypper.py +2 -0
  53. pyinfra/operations/apk.py +3 -1
  54. pyinfra/operations/apt.py +16 -18
  55. pyinfra/operations/brew.py +10 -8
  56. pyinfra/operations/bsdinit.py +5 -3
  57. pyinfra/operations/cargo.py +3 -1
  58. pyinfra/operations/choco.py +3 -1
  59. pyinfra/operations/dnf.py +15 -19
  60. pyinfra/operations/docker.py +339 -0
  61. pyinfra/operations/files.py +81 -66
  62. pyinfra/operations/gem.py +3 -1
  63. pyinfra/operations/git.py +18 -16
  64. pyinfra/operations/iptables.py +27 -25
  65. pyinfra/operations/launchd.py +5 -6
  66. pyinfra/operations/lxd.py +7 -4
  67. pyinfra/operations/mysql.py +57 -53
  68. pyinfra/operations/npm.py +8 -1
  69. pyinfra/operations/openrc.py +5 -3
  70. pyinfra/operations/pacman.py +4 -5
  71. pyinfra/operations/pip.py +11 -9
  72. pyinfra/operations/pkg.py +3 -1
  73. pyinfra/operations/pkgin.py +3 -1
  74. pyinfra/operations/postgres.py +39 -37
  75. pyinfra/operations/postgresql.py +2 -0
  76. pyinfra/operations/puppet.py +3 -1
  77. pyinfra/operations/python.py +7 -3
  78. pyinfra/operations/runit.py +182 -0
  79. pyinfra/operations/selinux.py +42 -16
  80. pyinfra/operations/server.py +52 -43
  81. pyinfra/operations/snap.py +3 -1
  82. pyinfra/operations/ssh.py +12 -10
  83. pyinfra/operations/systemd.py +12 -8
  84. pyinfra/operations/sysvinit.py +6 -4
  85. pyinfra/operations/upstart.py +5 -3
  86. pyinfra/operations/util/docker.py +177 -0
  87. pyinfra/operations/util/files.py +24 -16
  88. pyinfra/operations/util/packaging.py +53 -37
  89. pyinfra/operations/util/service.py +25 -18
  90. pyinfra/operations/vzctl.py +12 -10
  91. pyinfra/operations/xbps.py +3 -1
  92. pyinfra/operations/yum.py +14 -18
  93. pyinfra/operations/zypper.py +8 -9
  94. pyinfra/version.py +5 -2
  95. {pyinfra-3.0b1.dist-info → pyinfra-3.0b3.dist-info}/METADATA +30 -28
  96. pyinfra-3.0b3.dist-info/RECORD +167 -0
  97. {pyinfra-3.0b1.dist-info → pyinfra-3.0b3.dist-info}/WHEEL +1 -1
  98. pyinfra_cli/exceptions.py +0 -5
  99. pyinfra_cli/inventory.py +38 -19
  100. pyinfra_cli/prints.py +15 -11
  101. pyinfra_cli/util.py +3 -1
  102. tests/test_api/test_api_operations.py +1 -1
  103. tests/test_connectors/test_ssh.py +66 -13
  104. tests/test_connectors/test_vagrant.py +3 -3
  105. pyinfra-3.0b1.dist-info/RECORD +0 -163
  106. {pyinfra-3.0b1.dist-info → pyinfra-3.0b3.dist-info}/LICENSE.md +0 -0
  107. {pyinfra-3.0b1.dist-info → pyinfra-3.0b3.dist-info}/entry_points.txt +0 -0
  108. {pyinfra-3.0b1.dist-info → pyinfra-3.0b3.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,10 @@
2
2
  Manage systemd services.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
7
+ import shlex
8
+
5
9
  from pyinfra import host
6
10
  from pyinfra.api import StringCommand, operation
7
11
  from pyinfra.facts.systemd import SystemdEnabled, SystemdStatus, _make_systemctl_cmd
@@ -10,7 +14,7 @@ from .util.service import handle_service_control
10
14
 
11
15
 
12
16
  @operation(is_idempotent=False)
13
- def daemon_reload(user_mode=False, machine=None, user_name=None):
17
+ def daemon_reload(user_mode=False, machine: str | None = None, user_name: str | None = None):
14
18
  """
15
19
  Reload the systemd daemon to read unit file changes.
16
20
 
@@ -33,16 +37,16 @@ _daemon_reload = daemon_reload._inner # noqa: E305
33
37
 
34
38
  @operation()
35
39
  def service(
36
- service,
40
+ service: str,
37
41
  running=True,
38
42
  restarted=False,
39
43
  reloaded=False,
40
- command=None,
41
- enabled=None,
44
+ command: str | None = None,
45
+ enabled: bool | None = None,
42
46
  daemon_reload=False,
43
47
  user_mode=False,
44
- machine=None,
45
- user_name=None,
48
+ machine: str | None = None,
49
+ user_name: str | None = None,
46
50
  ):
47
51
  """
48
52
  Manage the state of systemd managed units.
@@ -138,8 +142,8 @@ def service(
138
142
 
139
143
  # Isn't enabled and want enabled?
140
144
  if not is_enabled and enabled is True:
141
- yield "{0} enable {1}".format(systemctl_cmd, service)
145
+ yield "{0} enable {1}".format(systemctl_cmd, shlex.quote(service))
142
146
 
143
147
  # Is enabled and want disabled?
144
148
  elif is_enabled and enabled is False:
145
- yield "{0} disable {1}".format(systemctl_cmd, service)
149
+ yield "{0} disable {1}".format(systemctl_cmd, shlex.quote(service))
@@ -2,6 +2,8 @@
2
2
  Manage sysvinit services (``/etc/init.d``).
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.files import FindLinks
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
14
16
 
15
17
  @operation()
16
18
  def service(
17
- service,
19
+ service: str,
18
20
  running=True,
19
21
  restarted=False,
20
22
  reloaded=False,
21
- enabled=None,
22
- command=None,
23
+ enabled: bool | None = None,
24
+ command: str | None = None,
23
25
  ):
24
26
  """
25
27
  Manage the state of SysV Init (/etc/init.d) services.
@@ -95,7 +97,7 @@ def service(
95
97
 
96
98
  @operation()
97
99
  def enable(
98
- service,
100
+ service: str,
99
101
  start_priority=20,
100
102
  stop_priority=80,
101
103
  start_levels=(2, 3, 4, 5),
@@ -2,6 +2,8 @@
2
2
  Manage upstart services.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from io import StringIO
6
8
 
7
9
  from pyinfra import host
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
14
16
 
15
17
  @operation()
16
18
  def service(
17
- service,
19
+ service: str,
18
20
  running=True,
19
21
  restarted=False,
20
22
  reloaded=False,
21
- command=None,
22
- enabled=None,
23
+ command: str | None = None,
24
+ enabled: bool | None = None,
23
25
  ):
24
26
  """
25
27
  Manage the state of upstart managed services.
@@ -0,0 +1,177 @@
1
+ from pyinfra.api import OperationError
2
+
3
+
4
+ def _create_container(**kwargs):
5
+ command = []
6
+
7
+ networks = kwargs["networks"] if kwargs["networks"] else []
8
+ ports = kwargs["ports"] if kwargs["ports"] else []
9
+ volumes = kwargs["volumes"] if kwargs["volumes"] else []
10
+ env_vars = kwargs["env_vars"] if kwargs["env_vars"] else []
11
+
12
+ if kwargs["image"] == "":
13
+ raise OperationError("missing 1 required argument: 'image'")
14
+
15
+ command.append("docker container create --name {0}".format(kwargs["container"]))
16
+
17
+ for network in networks:
18
+ command.append("--network {0}".format(network))
19
+
20
+ for port in ports:
21
+ command.append("-p {0}".format(port))
22
+
23
+ for volume in volumes:
24
+ command.append("-v {0}".format(volume))
25
+
26
+ for env_var in env_vars:
27
+ command.append("-e {0}".format(env_var))
28
+
29
+ if kwargs["pull_always"]:
30
+ command.append("--pull always")
31
+
32
+ command.append(kwargs["image"])
33
+
34
+ if kwargs["start"]:
35
+ command.append("; {0}".format(_start_container(container=kwargs["container"])))
36
+
37
+ return " ".join(command)
38
+
39
+
40
+ def _remove_container(**kwargs):
41
+ return "docker container rm -f {0}".format(kwargs["container"])
42
+
43
+
44
+ def _start_container(**kwargs):
45
+ return "docker container start {0}".format(kwargs["container"])
46
+
47
+
48
+ def _stop_container(**kwargs):
49
+ return "docker container stop {0}".format(kwargs["container"])
50
+
51
+
52
+ def _pull_image(**kwargs):
53
+ return "docker image pull {0}".format(kwargs["image"])
54
+
55
+
56
+ def _remove_image(**kwargs):
57
+ return "docker image rm {0}".format(kwargs["image"])
58
+
59
+
60
+ def _prune_command(**kwargs):
61
+ command = ["docker system prune"]
62
+
63
+ if kwargs["all"]:
64
+ command.append("-a")
65
+
66
+ if kwargs["filter"] != "":
67
+ command.append("--filter={0}".format(kwargs["filter"]))
68
+
69
+ if kwargs["volumes"]:
70
+ command.append("--volumes")
71
+
72
+ command.append("-f")
73
+
74
+ return " ".join(command)
75
+
76
+
77
+ def _create_volume(**kwargs):
78
+ command = []
79
+ labels = kwargs["labels"] if kwargs["labels"] else []
80
+
81
+ command.append("docker volume create {0}".format(kwargs["volume"]))
82
+
83
+ if kwargs["driver"] != "":
84
+ command.append("-d {0}".format(kwargs["driver"]))
85
+
86
+ for label in labels:
87
+ command.append("--label {0}".format(label))
88
+
89
+ return " ".join(command)
90
+
91
+
92
+ def _remove_volume(**kwargs):
93
+ return "docker image rm {0}".format(kwargs["volume"])
94
+
95
+
96
+ def _create_network(**kwargs):
97
+ command = []
98
+ opts = kwargs["opts"] if kwargs["opts"] else []
99
+ ipam_opts = kwargs["ipam_opts"] if kwargs["ipam_opts"] else []
100
+ labels = kwargs["labels"] if kwargs["labels"] else []
101
+
102
+ command.append("docker network create {0}".format(kwargs["network"]))
103
+ if kwargs["driver"] != "":
104
+ command.append("-d {0}".format(kwargs["driver"]))
105
+
106
+ if kwargs["gateway"] != "":
107
+ command.append("--gateway {0}".format(kwargs["gateway"]))
108
+
109
+ if kwargs["ip_range"] != "":
110
+ command.append("--ip-range {0}".format(kwargs["ip_range"]))
111
+
112
+ if kwargs["ipam_driver"] != "":
113
+ command.append("--ipam-driver {0}".format(kwargs["ipam_driver"]))
114
+
115
+ if kwargs["subnet"] != "":
116
+ command.append("--subnet {0}".format(kwargs["subnet"]))
117
+
118
+ if kwargs["scope"] != "":
119
+ command.append("--scope {0}".format(kwargs["scope"]))
120
+
121
+ if kwargs["ingress"]:
122
+ command.append("--ingress")
123
+
124
+ if kwargs["attachable"]:
125
+ command.append("--attachable")
126
+
127
+ for opt in opts:
128
+ command.append("--opt {0}".format(opt))
129
+
130
+ for opt in ipam_opts:
131
+ command.append("--ipam-opt {0}".format(opt))
132
+
133
+ for label in labels:
134
+ command.append("--label {0}".format(label))
135
+ return " ".join(command)
136
+
137
+
138
+ def _remove_network(**kwargs):
139
+ return "docker network rm {0}".format(kwargs["network"])
140
+
141
+
142
+ def handle_docker(resource, command, **kwargs):
143
+ container_commands = {
144
+ "create": _create_container,
145
+ "remove": _remove_container,
146
+ "start": _start_container,
147
+ "stop": _stop_container,
148
+ }
149
+
150
+ image_commands = {
151
+ "pull": _pull_image,
152
+ "remove": _remove_image,
153
+ }
154
+
155
+ volume_commands = {
156
+ "create": _create_volume,
157
+ "remove": _remove_volume,
158
+ }
159
+
160
+ network_commands = {
161
+ "create": _create_network,
162
+ "remove": _remove_network,
163
+ }
164
+
165
+ system_commands = {
166
+ "prune": _prune_command,
167
+ }
168
+
169
+ docker_commands = {
170
+ "container": container_commands,
171
+ "image": image_commands,
172
+ "volume": volume_commands,
173
+ "network": network_commands,
174
+ "system": system_commands,
175
+ }
176
+
177
+ return docker_commands[resource][command](**kwargs)
@@ -1,16 +1,18 @@
1
+ from __future__ import annotations
2
+
1
3
  import re
2
4
  from datetime import datetime
3
5
 
4
6
  from pyinfra.api import QuoteString, StringCommand
5
7
 
6
8
 
7
- def unix_path_join(*path_parts):
8
- parts = list(path_parts)
9
- parts[0:-1] = [part.rstrip("/") for part in parts[0:-1]]
10
- return "/".join(parts)
9
+ def unix_path_join(*parts) -> str:
10
+ part_list = list(parts)
11
+ part_list[0:-1] = [part.rstrip("/") for part in part_list[0:-1]]
12
+ return "/".join(part_list)
11
13
 
12
14
 
13
- def ensure_mode_int(mode):
15
+ def ensure_mode_int(mode: str | int | None) -> int | str | None:
14
16
  # Already an int (/None)?
15
17
  if isinstance(mode, int) or mode is None:
16
18
  return mode
@@ -26,19 +28,19 @@ def ensure_mode_int(mode):
26
28
  return mode
27
29
 
28
30
 
29
- def get_timestamp():
31
+ def get_timestamp() -> str:
30
32
  return datetime.now().strftime("%y%m%d%H%M")
31
33
 
32
34
 
33
35
  def sed_replace(
34
- filename,
35
- line,
36
- replace,
37
- flags=None,
36
+ filename: str,
37
+ line: str,
38
+ replace: str,
39
+ flags: list[str] | None = None,
38
40
  backup=False,
39
41
  interpolate_variables=False,
40
- ):
41
- flags = "".join(flags) if flags else ""
42
+ ) -> StringCommand:
43
+ flags_str = "".join(flags) if flags else ""
42
44
 
43
45
  line = line.replace("/", r"\/")
44
46
  replace = str(replace)
@@ -57,7 +59,7 @@ def sed_replace(
57
59
  replace = replace.replace("'", "'\"'\"'")
58
60
  sed_script_formatter = "'s/{0}/{1}/{2}'"
59
61
 
60
- sed_script = sed_script_formatter.format(line, replace, flags)
62
+ sed_script = sed_script_formatter.format(line, replace, flags_str)
61
63
 
62
64
  sed_command = StringCommand(
63
65
  "sed",
@@ -73,7 +75,7 @@ def sed_replace(
73
75
  return sed_command
74
76
 
75
77
 
76
- def chmod(target, mode, recursive=False):
78
+ def chmod(target: str, mode: str | int, recursive=False) -> StringCommand:
77
79
  args = ["chmod"]
78
80
  if recursive:
79
81
  args.append("-R")
@@ -83,7 +85,13 @@ def chmod(target, mode, recursive=False):
83
85
  return StringCommand(" ".join(args), QuoteString(target))
84
86
 
85
87
 
86
- def chown(target, user, group=None, recursive=False, dereference=True):
88
+ def chown(
89
+ target: str,
90
+ user: str | None = None,
91
+ group: str | None = None,
92
+ recursive=False,
93
+ dereference=True,
94
+ ) -> StringCommand:
87
95
  command = "chown"
88
96
  user_group = None
89
97
 
@@ -107,7 +115,7 @@ def chown(target, user, group=None, recursive=False, dereference=True):
107
115
  return StringCommand(" ".join(args), user_group, QuoteString(target))
108
116
 
109
117
 
110
- def adjust_regex(line, escape_regex_characters):
118
+ def adjust_regex(line: str, escape_regex_characters: bool) -> str:
111
119
  """
112
120
  Ensure the regex starts with '^' and ends with '$' and escape regex characters if requested
113
121
  """
@@ -1,19 +1,29 @@
1
+ from __future__ import annotations
2
+
1
3
  import shlex
2
4
  from collections import defaultdict
3
5
  from io import StringIO
6
+ from typing import Callable
4
7
  from urllib.parse import urlparse
5
8
 
9
+ from pyinfra.api import Host, State
6
10
  from pyinfra.facts.files import File
7
11
  from pyinfra.facts.rpm import RpmPackage
12
+ from pyinfra.operations import files
8
13
 
9
14
 
10
- def _package_name(package):
15
+ def _package_name(package: list[str] | str) -> str:
11
16
  if isinstance(package, list):
12
17
  return package[0]
13
18
  return package
14
19
 
15
20
 
16
- def _has_package(package, packages, expand_package_fact=None, match_any=False):
21
+ def _has_package(
22
+ package: str | list[str],
23
+ packages: dict[str, set[str]],
24
+ expand_package_fact: Callable[[str], list[str | list[str]]] | None = None,
25
+ match_any=False,
26
+ ) -> tuple[bool, dict]:
17
27
  def in_packages(pkg_name, pkg_versions):
18
28
  if not pkg_versions:
19
29
  return pkg_name in packages
@@ -21,9 +31,12 @@ def _has_package(package, packages, expand_package_fact=None, match_any=False):
21
31
  version in packages[pkg_name] for version in pkg_versions
22
32
  )
23
33
 
24
- packages_to_check = [package]
34
+ packages_to_check: list[str | list[str]] = [package]
25
35
  if expand_package_fact:
26
- packages_to_check = expand_package_fact(package) or packages_to_check
36
+ if isinstance(package, list):
37
+ packages_to_check = expand_package_fact(package[0]) or packages_to_check
38
+ else:
39
+ packages_to_check = expand_package_fact(package) or packages_to_check
27
40
 
28
41
  package_name_to_versions = defaultdict(set)
29
42
  for pkg in packages_to_check:
@@ -43,16 +56,16 @@ def _has_package(package, packages, expand_package_fact=None, match_any=False):
43
56
 
44
57
 
45
58
  def ensure_packages(
46
- host,
47
- packages,
48
- current_packages,
49
- present,
50
- install_command,
51
- uninstall_command,
59
+ host: Host,
60
+ packages_to_ensure: str | list[str] | None,
61
+ current_packages: dict[str, set[str]],
62
+ present: bool,
63
+ install_command: str,
64
+ uninstall_command: str,
52
65
  latest=False,
53
- upgrade_command=None,
54
- version_join=None,
55
- expand_package_fact=None,
66
+ upgrade_command: str | None = None,
67
+ version_join: str | None = None,
68
+ expand_package_fact: Callable[[str], list[str | list[str]]] | None = None,
56
69
  ):
57
70
  """
58
71
  Handles this common scenario:
@@ -64,7 +77,7 @@ def ensure_packages(
64
77
  + Optionally upgrades packages w/o specified version when present
65
78
 
66
79
  Args:
67
- packages (list): list of packages or package/versions
80
+ packages_to_ensure (list): list of packages or package/versions
68
81
  current_packages (fact): fact returning dict of package names -> version
69
82
  present (bool): whether packages should exist or not
70
83
  install_command (str): command to prefix to list of packages to install
@@ -73,18 +86,21 @@ def ensure_packages(
73
86
  upgrade_command (str): as above for upgrading
74
87
  version_join (str): the package manager specific "joiner", ie ``=`` for \
75
88
  ``<apt_pkg>=<version>``
89
+ expand_package_fact: fact returning packages providing a capability \
90
+ (ie ``yum whatprovides``)
76
91
  """
77
92
 
78
- if packages is None:
93
+ if packages_to_ensure is None:
79
94
  return
95
+ if isinstance(packages_to_ensure, str):
96
+ packages_to_ensure = [packages_to_ensure]
80
97
 
81
- if isinstance(packages, str):
82
- packages = [packages]
98
+ packages: list[str | list[str]] = packages_to_ensure # type: ignore[assignment]
83
99
 
84
100
  if version_join:
85
101
  packages = [
86
102
  package[0] if len(package) == 1 else package
87
- for package in [package.rsplit(version_join, 1) for package in packages]
103
+ for package in [package.rsplit(version_join, 1) for package in packages] # type: ignore[union-attr] # noqa
88
104
  ]
89
105
 
90
106
  diff_packages = []
@@ -140,7 +156,7 @@ def ensure_packages(
140
156
  command = install_command if present else uninstall_command
141
157
 
142
158
  joined_packages = [
143
- version_join.join(package) if isinstance(package, list) else package
159
+ version_join.join(package) if isinstance(package, list) else package # type: ignore[union-attr] # noqa
144
160
  for package in diff_packages
145
161
  ]
146
162
 
@@ -156,7 +172,7 @@ def ensure_packages(
156
172
  )
157
173
 
158
174
 
159
- def ensure_rpm(state, host, files, source, present, package_manager_command):
175
+ def ensure_rpm(state: State, host: Host, source: str, present: bool, package_manager_command: str):
160
176
  original_source = source
161
177
 
162
178
  # If source is a url
@@ -165,18 +181,18 @@ def ensure_rpm(state, host, files, source, present, package_manager_command):
165
181
  temp_filename = "{0}.rpm".format(host.get_temp_filename(source))
166
182
 
167
183
  # Ensure it's downloaded
168
- yield from files.download._inner(source, temp_filename)
184
+ yield from files.download._inner(src=source, dest=temp_filename)
169
185
 
170
186
  # Override the source with the downloaded file
171
187
  source = temp_filename
172
188
 
173
189
  # Check for file .rpm information
174
- info = host.get_fact(RpmPackage, name=source)
190
+ info = host.get_fact(RpmPackage, package=source)
175
191
  exists = False
176
192
 
177
193
  # We have info!
178
194
  if info:
179
- current_package = host.get_fact(RpmPackage, name=info["name"])
195
+ current_package = host.get_fact(RpmPackage, package=info["name"])
180
196
  if current_package and current_package["version"] == info["version"]:
181
197
  exists = True
182
198
 
@@ -204,18 +220,16 @@ def ensure_rpm(state, host, files, source, present, package_manager_command):
204
220
 
205
221
 
206
222
  def ensure_yum_repo(
207
- state,
208
- host,
209
- files,
210
- name_or_url,
211
- baseurl,
212
- present,
213
- description,
214
- enabled,
215
- gpgcheck,
216
- gpgkey,
223
+ host: Host,
224
+ name_or_url: str,
225
+ baseurl: str | None,
226
+ present: bool,
227
+ description: str | None,
228
+ enabled: bool,
229
+ gpgcheck: bool,
230
+ gpgkey: str | None,
217
231
  repo_directory="/etc/yum.repos.d/",
218
- type_=None,
232
+ type_: str | None = None,
219
233
  ):
220
234
  url = None
221
235
  url_parts = urlparse(name_or_url)
@@ -229,15 +243,17 @@ def ensure_yum_repo(
229
243
 
230
244
  # If we don't want the repo, just remove any existing file
231
245
  if not present:
232
- yield from files.file._inner(filename, present=False)
246
+ yield from files.file._inner(path=filename, present=False)
233
247
  return
234
248
 
235
249
  # If we're a URL, download the repo if it doesn't exist
236
250
  if url:
237
251
  if not host.get_fact(File, path=filename):
238
- yield from files.download._inner(url, filename)
252
+ yield from files.download._inner(src=url, dest=filename)
239
253
  return
240
254
 
255
+ assert isinstance(baseurl, str)
256
+
241
257
  # Description defaults to name
242
258
  description = description or name_or_url
243
259
 
@@ -261,4 +277,4 @@ def ensure_yum_repo(
261
277
  repo_file = StringIO(repo)
262
278
 
263
279
  # Ensure this is the file on the server
264
- yield from files.put._inner(repo_file, filename)
280
+ yield from files.put._inner(src=repo_file, dest=filename)
@@ -1,39 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ import shlex
4
+
5
+ from pyinfra.api import Host
6
+
7
+
1
8
  def handle_service_control(
2
- host,
3
- name,
4
- statuses,
5
- formatter,
6
- running,
7
- restarted,
8
- reloaded,
9
- command,
9
+ host: Host,
10
+ name: str,
11
+ statuses: dict[str, bool],
12
+ formatter: str,
13
+ running: bool | None = None,
14
+ restarted: bool | None = None,
15
+ reloaded: bool | None = None,
16
+ command: str | None = None,
10
17
  status_argument="status",
11
18
  ):
12
- status = statuses.get(name, None)
19
+ is_running = statuses.get(name, None)
13
20
 
14
21
  # Need down but running
15
22
  if running is False:
16
- if status:
17
- yield formatter.format(name, "stop")
23
+ if is_running:
24
+ yield formatter.format(shlex.quote(name), "stop")
18
25
  else:
19
26
  host.noop("service {0} is stopped".format(name))
20
27
 
21
28
  # Need running but down
22
29
  if running is True:
23
- if not status:
24
- yield formatter.format(name, "start")
30
+ if not is_running:
31
+ yield formatter.format(shlex.quote(name), "start")
25
32
  else:
26
33
  host.noop("service {0} is running".format(name))
27
34
 
28
35
  # Only restart if the service is already running
29
- if restarted and status:
30
- yield formatter.format(name, "restart")
36
+ if restarted and is_running:
37
+ yield formatter.format(shlex.quote(name), "restart")
31
38
 
32
39
  # Only reload if the service is already reloaded
33
- if reloaded and status:
34
- yield formatter.format(name, "reload")
40
+ if reloaded and is_running:
41
+ yield formatter.format(shlex.quote(name), "reload")
35
42
 
36
43
  # Always execute arbitrary commands as these may or may not rely on the service
37
44
  # being up or down
38
45
  if command:
39
- yield formatter.format(name, command)
46
+ yield formatter.format(shlex.quote(name), command)