pyinfra 3.2__py2.py3-none-any.whl → 3.3__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 (88) hide show
  1. pyinfra/api/arguments_typed.py +4 -5
  2. pyinfra/api/command.py +22 -3
  3. pyinfra/api/config.py +5 -2
  4. pyinfra/api/facts.py +3 -0
  5. pyinfra/api/host.py +10 -4
  6. pyinfra/api/operation.py +2 -1
  7. pyinfra/api/state.py +1 -1
  8. pyinfra/connectors/base.py +34 -8
  9. pyinfra/connectors/chroot.py +7 -2
  10. pyinfra/connectors/docker.py +7 -2
  11. pyinfra/connectors/dockerssh.py +7 -2
  12. pyinfra/connectors/local.py +7 -2
  13. pyinfra/connectors/ssh.py +9 -2
  14. pyinfra/connectors/sshuserclient/client.py +16 -0
  15. pyinfra/connectors/sshuserclient/config.py +2 -0
  16. pyinfra/connectors/terraform.py +1 -1
  17. pyinfra/connectors/util.py +13 -9
  18. pyinfra/context.py +9 -2
  19. pyinfra/facts/apk.py +5 -0
  20. pyinfra/facts/apt.py +9 -1
  21. pyinfra/facts/brew.py +13 -0
  22. pyinfra/facts/bsdinit.py +3 -0
  23. pyinfra/facts/cargo.py +5 -0
  24. pyinfra/facts/choco.py +6 -0
  25. pyinfra/facts/crontab.py +6 -1
  26. pyinfra/facts/deb.py +10 -0
  27. pyinfra/facts/dnf.py +5 -0
  28. pyinfra/facts/docker.py +10 -0
  29. pyinfra/facts/efibootmgr.py +5 -0
  30. pyinfra/facts/files.py +19 -1
  31. pyinfra/facts/flatpak.py +7 -0
  32. pyinfra/facts/freebsd.py +75 -0
  33. pyinfra/facts/gem.py +5 -0
  34. pyinfra/facts/git.py +9 -0
  35. pyinfra/facts/gpg.py +7 -0
  36. pyinfra/facts/hardware.py +13 -0
  37. pyinfra/facts/iptables.py +9 -1
  38. pyinfra/facts/launchd.py +5 -0
  39. pyinfra/facts/lxd.py +5 -0
  40. pyinfra/facts/mysql.py +8 -0
  41. pyinfra/facts/npm.py +5 -0
  42. pyinfra/facts/openrc.py +8 -0
  43. pyinfra/facts/opkg.py +12 -0
  44. pyinfra/facts/pacman.py +9 -1
  45. pyinfra/facts/pip.py +5 -0
  46. pyinfra/facts/pipx.py +8 -0
  47. pyinfra/facts/pkg.py +4 -0
  48. pyinfra/facts/pkgin.py +5 -0
  49. pyinfra/facts/podman.py +7 -0
  50. pyinfra/facts/postgres.py +8 -2
  51. pyinfra/facts/rpm.py +11 -0
  52. pyinfra/facts/runit.py +7 -0
  53. pyinfra/facts/selinux.py +16 -0
  54. pyinfra/facts/server.py +49 -3
  55. pyinfra/facts/snap.py +7 -0
  56. pyinfra/facts/systemd.py +5 -0
  57. pyinfra/facts/sysvinit.py +4 -0
  58. pyinfra/facts/upstart.py +5 -0
  59. pyinfra/facts/util/__init__.py +4 -1
  60. pyinfra/facts/vzctl.py +5 -0
  61. pyinfra/facts/xbps.py +6 -1
  62. pyinfra/facts/yum.py +5 -0
  63. pyinfra/facts/zfs.py +19 -2
  64. pyinfra/facts/zypper.py +5 -0
  65. pyinfra/operations/apt.py +10 -3
  66. pyinfra/operations/docker.py +48 -44
  67. pyinfra/operations/files.py +47 -1
  68. pyinfra/operations/freebsd/__init__.py +12 -0
  69. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  70. pyinfra/operations/freebsd/pkg.py +219 -0
  71. pyinfra/operations/freebsd/service.py +116 -0
  72. pyinfra/operations/freebsd/sysrc.py +92 -0
  73. pyinfra/operations/opkg.py +5 -5
  74. pyinfra/operations/postgres.py +99 -16
  75. pyinfra/operations/server.py +6 -4
  76. pyinfra/operations/util/docker.py +44 -22
  77. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/LICENSE.md +1 -1
  78. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/METADATA +25 -24
  79. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/RECORD +88 -82
  80. pyinfra_cli/exceptions.py +5 -0
  81. pyinfra_cli/log.py +3 -0
  82. pyinfra_cli/main.py +9 -8
  83. pyinfra_cli/prints.py +1 -1
  84. pyinfra_cli/virtualenv.py +1 -1
  85. tests/test_connectors/test_ssh.py +302 -182
  86. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/WHEEL +0 -0
  87. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/entry_points.txt +0 -0
  88. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/top_level.txt +0 -0
pyinfra/facts/opkg.py CHANGED
@@ -12,6 +12,8 @@ Gather the information provided by ``opkg`` on OpenWrt systems:
12
12
  import re
13
13
  from typing import Dict, NamedTuple, Union
14
14
 
15
+ from typing_extensions import override
16
+
15
17
  from pyinfra import logger
16
18
  from pyinfra.api import FactBase
17
19
  from pyinfra.facts.util.packaging import parse_packages
@@ -83,9 +85,11 @@ class OpkgConf(FactBase):
83
85
  def default():
84
86
  return OpkgConfInfo({}, "", {}, {})
85
87
 
88
+ @override
86
89
  def command(self) -> str:
87
90
  return "cat /etc/opkg.conf"
88
91
 
92
+ @override
89
93
  def process(self, output):
90
94
  dest, lists_dir, options, arch_cfg = {}, "", {}, {}
91
95
  for line in output:
@@ -127,9 +131,11 @@ class OpkgFeeds(FactBase):
127
131
  )
128
132
  default = dict
129
133
 
134
+ @override
130
135
  def command(self) -> str:
131
136
  return "cat /etc/opkg/distfeeds.conf; echo CUSTOM; cat /etc/opkg/customfeeds.conf"
132
137
 
138
+ @override
133
139
  def process(self, output):
134
140
  feeds, kind = {}, "distribution"
135
141
  for line in output:
@@ -164,9 +170,11 @@ class OpkgInstallableArchitectures(FactBase):
164
170
  regex = re.compile(r"^(?:\s*arch\s+(?P<arch>[\w]+)\s+(?P<prio>\d+))?(\s*#.*)?$")
165
171
  default = dict
166
172
 
173
+ @override
167
174
  def command(self) -> str:
168
175
  return "/bin/opkg print-architecture"
169
176
 
177
+ @override
170
178
  def process(self, output):
171
179
  arch_list = {}
172
180
  for line in output:
@@ -195,9 +203,11 @@ class OpkgPackages(FactBase):
195
203
  regex = r"^([a-zA-Z0-9][\w\-\.]*)\s-\s([\w\-\.]+)"
196
204
  default = dict
197
205
 
206
+ @override
198
207
  def command(self) -> str:
199
208
  return "/bin/opkg list-installed"
200
209
 
210
+ @override
201
211
  def process(self, output):
202
212
  return parse_packages(self.regex, sorted(output))
203
213
 
@@ -218,9 +228,11 @@ class OpkgUpgradeablePackages(FactBase):
218
228
  default = dict
219
229
  use_default_on_error = True
220
230
 
231
+ @override
221
232
  def command(self) -> str:
222
233
  return "/bin/opkg list-upgradable" # yes, really spelled that way
223
234
 
235
+ @override
224
236
  def process(self, output):
225
237
  result = {}
226
238
  for line in output:
pyinfra/facts/pacman.py CHANGED
@@ -2,11 +2,13 @@ from __future__ import annotations
2
2
 
3
3
  import shlex
4
4
 
5
+ from typing_extensions import override
6
+
5
7
  from pyinfra.api import FactBase
6
8
 
7
9
  from .util.packaging import parse_packages
8
10
 
9
- PACMAN_REGEX = r"^([0-9a-zA-Z\-]+)\s([0-9\._+a-z\-]+)"
11
+ PACMAN_REGEX = r"^([0-9a-zA-Z\-_]+)\s([0-9\._+a-z\-:]+)"
10
12
 
11
13
 
12
14
  class PacmanUnpackGroup(FactBase):
@@ -21,15 +23,18 @@ class PacmanUnpackGroup(FactBase):
21
23
  ]
22
24
  """
23
25
 
26
+ @override
24
27
  def requires_command(self, *args, **kwargs) -> str:
25
28
  return "pacman"
26
29
 
27
30
  default = list
28
31
 
32
+ @override
29
33
  def command(self, package):
30
34
  # Accept failure here (|| true) for invalid/unknown packages
31
35
  return 'pacman -S --print-format "%n" {0} || true'.format(shlex.quote(package))
32
36
 
37
+ @override
33
38
  def process(self, output):
34
39
  return output
35
40
 
@@ -45,13 +50,16 @@ class PacmanPackages(FactBase):
45
50
  }
46
51
  """
47
52
 
53
+ @override
48
54
  def command(self) -> str:
49
55
  return "pacman -Q"
50
56
 
57
+ @override
51
58
  def requires_command(self, *args, **kwargs) -> str:
52
59
  return "pacman"
53
60
 
54
61
  default = dict
55
62
 
63
+ @override
56
64
  def process(self, output):
57
65
  return parse_packages(PACMAN_REGEX, output)
pyinfra/facts/pip.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -21,13 +23,16 @@ class PipPackages(FactBase):
21
23
  default = dict
22
24
  pip_command = "pip"
23
25
 
26
+ @override
24
27
  def requires_command(self, pip=None):
25
28
  return pip or self.pip_command
26
29
 
30
+ @override
27
31
  def command(self, pip=None):
28
32
  pip = pip or self.pip_command
29
33
  return "{0} freeze --all".format(pip)
30
34
 
35
+ @override
31
36
  def process(self, output):
32
37
  return parse_packages(PIP_REGEX, output)
33
38
 
pyinfra/facts/pipx.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import re
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -35,12 +37,15 @@ class PipxPackages(FactBase):
35
37
 
36
38
  default = dict
37
39
 
40
+ @override
38
41
  def requires_command(self) -> str:
39
42
  return "pipx"
40
43
 
44
+ @override
41
45
  def command(self) -> str:
42
46
  return "pipx list --short"
43
47
 
48
+ @override
44
49
  def process(self, output):
45
50
  return parse_packages(PIPX_REGEX, output)
46
51
 
@@ -64,11 +69,14 @@ class PipxEnvironment(FactBase):
64
69
 
65
70
  default = dict
66
71
 
72
+ @override
67
73
  def requires_command(self) -> str:
68
74
  return "pipx"
69
75
 
76
+ @override
70
77
  def command(self) -> str:
71
78
  return "pipx environment"
72
79
 
80
+ @override
73
81
  def process(self, output):
74
82
  return parse_environment(output)
pyinfra/facts/pkg.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -19,8 +21,10 @@ class PkgPackages(FactBase):
19
21
  regex = r"^([a-zA-Z0-9_\-\+]+)\-([0-9a-z\.]+)"
20
22
  default = dict
21
23
 
24
+ @override
22
25
  def command(self) -> str:
23
26
  return "pkg info || pkg_info || true"
24
27
 
28
+ @override
25
29
  def process(self, output):
26
30
  return parse_packages(self.regex, output)
pyinfra/facts/pkgin.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -18,13 +20,16 @@ class PkginPackages(FactBase):
18
20
  }
19
21
  """
20
22
 
23
+ @override
21
24
  def command(self) -> str:
22
25
  return "pkgin list"
23
26
 
27
+ @override
24
28
  def requires_command(self) -> str:
25
29
  return "pkgin"
26
30
 
27
31
  default = dict
28
32
 
33
+ @override
29
34
  def process(self, output):
30
35
  return parse_packages(PKGIN_REGEX, output)
pyinfra/facts/podman.py CHANGED
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  import json
4
4
  from typing import Any, Dict, Iterable, List, TypeVar
5
5
 
6
+ from typing_extensions import override
7
+
6
8
  from pyinfra.api import FactBase
7
9
 
8
10
  T = TypeVar("T")
@@ -15,6 +17,7 @@ class PodmanFactBase(FactBase[T]):
15
17
 
16
18
  abstract = True
17
19
 
20
+ @override
18
21
  def requires_command(self, *args, **kwargs) -> str:
19
22
  return "podman"
20
23
 
@@ -24,9 +27,11 @@ class PodmanSystemInfo(PodmanFactBase[Dict[str, Any]]):
24
27
  Output of 'podman system info'
25
28
  """
26
29
 
30
+ @override
27
31
  def command(self) -> str:
28
32
  return "podman system info --format=json"
29
33
 
34
+ @override
30
35
  def process(self, output: Iterable[str]) -> Dict[str, Any]:
31
36
  output = json.loads(("").join(output))
32
37
  assert isinstance(output, dict)
@@ -38,9 +43,11 @@ class PodmanPs(PodmanFactBase[List[Dict[str, Any]]]):
38
43
  Output of 'podman ps'
39
44
  """
40
45
 
46
+ @override
41
47
  def command(self) -> str:
42
48
  return "podman ps --format=json --all"
43
49
 
50
+ @override
44
51
  def process(self, output: Iterable[str]) -> List[Dict[str, Any]]:
45
52
  output = json.loads(("").join(output))
46
53
  assert isinstance(output, list)
pyinfra/facts/postgres.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase, MaskString, QuoteString, StringCommand
4
6
  from pyinfra.api.util import try_int
5
7
 
@@ -49,9 +51,11 @@ class PostgresFactBase(FactBase):
49
51
 
50
52
  psql_command: str
51
53
 
54
+ @override
52
55
  def requires_command(self, *args, **kwargs):
53
56
  return "psql"
54
57
 
58
+ @override
55
59
  def command(
56
60
  self,
57
61
  psql_user=None,
@@ -89,6 +93,7 @@ class PostgresRoles(PostgresFactBase):
89
93
  default = dict
90
94
  psql_command = "SELECT * FROM pg_catalog.pg_roles"
91
95
 
96
+ @override
92
97
  def process(self, output):
93
98
  # Remove the last line of the output (row count)
94
99
  output = output[:-1]
@@ -139,8 +144,9 @@ class PostgresDatabases(PostgresFactBase):
139
144
  """
140
145
 
141
146
  default = dict
142
- psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database"
147
+ psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), *, pg_catalog.pg_get_userbyid(datdba) AS owner FROM pg_catalog.pg_database" # noqa: E501
143
148
 
149
+ @override
144
150
  def process(self, output):
145
151
  # Remove the last line of the output (row count)
146
152
  output = output[:-1]
@@ -155,7 +161,7 @@ class PostgresDatabases(PostgresFactBase):
155
161
 
156
162
  for details in rows:
157
163
  details["encoding"] = details.pop("pg_encoding_to_char")
158
-
164
+ details["owner"] = details.pop("owner")
159
165
  for key, value in list(details.items()):
160
166
  if key.endswith("id") or key in (
161
167
  "dba",
pyinfra/facts/rpm.py CHANGED
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  import re
4
4
  import shlex
5
5
 
6
+ from typing_extensions import override
7
+
6
8
  from pyinfra.api import FactBase
7
9
 
8
10
  from .util.packaging import parse_packages
@@ -22,14 +24,17 @@ class RpmPackages(FactBase):
22
24
  }
23
25
  """
24
26
 
27
+ @override
25
28
  def command(self) -> str:
26
29
  return "rpm --queryformat {0} -qa".format(shlex.quote(rpm_query_format))
27
30
 
31
+ @override
28
32
  def requires_command(self) -> str:
29
33
  return "rpm"
30
34
 
31
35
  default = dict
32
36
 
37
+ @override
33
38
  def process(self, output):
34
39
  return parse_packages(rpm_regex, output)
35
40
 
@@ -46,9 +51,11 @@ class RpmPackage(FactBase):
46
51
  }
47
52
  """
48
53
 
54
+ @override
49
55
  def requires_command(self, package) -> str:
50
56
  return "rpm"
51
57
 
58
+ @override
52
59
  def command(self, package) -> str:
53
60
  return (
54
61
  "rpm --queryformat {0} -q {1} || "
@@ -56,6 +63,7 @@ class RpmPackage(FactBase):
56
63
  "rpm --queryformat {0} -qp {1} 2> /dev/null"
57
64
  ).format(shlex.quote(rpm_query_format), shlex.quote(package))
58
65
 
66
+ @override
59
67
  def process(self, output):
60
68
  for line in output:
61
69
  matches = re.match(rpm_regex, line)
@@ -73,9 +81,11 @@ class RpmPackageProvides(FactBase):
73
81
 
74
82
  default = list
75
83
 
84
+ @override
76
85
  def requires_command(self, *args, **kwargs) -> str:
77
86
  return "repoquery"
78
87
 
88
+ @override
79
89
  def command(self, package):
80
90
  # Accept failure here (|| true) for invalid/unknown packages
81
91
  return "repoquery --queryformat {0} --whatprovides {1} || true".format(
@@ -83,6 +93,7 @@ class RpmPackageProvides(FactBase):
83
93
  shlex.quote(package),
84
94
  )
85
95
 
96
+ @override
86
97
  def process(self, output):
87
98
  packages = []
88
99
 
pyinfra/facts/runit.py CHANGED
@@ -1,3 +1,5 @@
1
+ from typing_extensions import override
2
+
1
3
  from pyinfra.api import FactBase
2
4
 
3
5
 
@@ -20,9 +22,11 @@ class RunitStatus(FactBase):
20
22
 
21
23
  default = dict
22
24
 
25
+ @override
23
26
  def requires_command(self, *args, **kwargs) -> str:
24
27
  return "sv"
25
28
 
29
+ @override
26
30
  def command(self, service=None, svdir="/var/service") -> str:
27
31
  if service is None:
28
32
  return (
@@ -32,6 +36,7 @@ class RunitStatus(FactBase):
32
36
  else:
33
37
  return 'SVDIR="{0}" sv status "{1}"'.format(svdir, service)
34
38
 
39
+ @override
35
40
  def process(self, output):
36
41
  services = {}
37
42
  for line in output:
@@ -60,11 +65,13 @@ class RunitManaged(FactBase):
60
65
 
61
66
  default = set
62
67
 
68
+ @override
63
69
  def command(self, service=None, svdir="/var/service"):
64
70
  if service is None:
65
71
  return 'cd "{0}" && find -mindepth 1 -maxdepth 1 -type l -printf "%f\n"'.format(svdir)
66
72
  else:
67
73
  return 'cd "{0}" && test -h "{1}" && echo "{1}" || true'.format(svdir, service)
68
74
 
75
+ @override
69
76
  def process(self, output):
70
77
  return set(output)
pyinfra/facts/selinux.py CHANGED
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  import re
4
4
  from collections import defaultdict
5
5
 
6
+ from typing_extensions import override
7
+
6
8
  from pyinfra.api import FactBase
7
9
 
8
10
  FIELDS = ["user", "role", "type", "level"] # order is significant, do not change
@@ -14,14 +16,17 @@ class SEBoolean(FactBase):
14
16
  If ``boolean`` does not exist, ``SEBoolean`` returns the empty string.
15
17
  """
16
18
 
19
+ @override
17
20
  def requires_command(self, boolean) -> str:
18
21
  return "getsebool"
19
22
 
20
23
  default = str
21
24
 
25
+ @override
22
26
  def command(self, boolean):
23
27
  return "getsebool {0}".format(boolean)
24
28
 
29
+ @override
25
30
  def process(self, output):
26
31
  components = output[0].split(" --> ")
27
32
  return components[1]
@@ -42,9 +47,11 @@ class FileContext(FactBase):
42
47
  }
43
48
  """
44
49
 
50
+ @override
45
51
  def command(self, path):
46
52
  return "stat -c %C {0} || exit 0".format(path)
47
53
 
54
+ @override
48
55
  def process(self, output):
49
56
  context = {}
50
57
  components = output[0].split(":")
@@ -65,12 +72,15 @@ class FileContextMapping(FactBase):
65
72
 
66
73
  default = dict
67
74
 
75
+ @override
68
76
  def requires_command(self, target) -> str:
69
77
  return "semanage"
70
78
 
79
+ @override
71
80
  def command(self, target):
72
81
  return "set -o pipefail && semanage fcontext -n -l | (grep '^{0}' || true)".format(target)
73
82
 
83
+ @override
74
84
  def process(self, output):
75
85
  # example output: /etc all files system_u:object_r:etc_t:s0 # noqa: SC100
76
86
  # but lines at end that won't match: /etc/systemd/system = /usr/lib/systemd/system
@@ -97,12 +107,15 @@ class SEPorts(FactBase):
97
107
  # example output: amqp_port_t tcp 15672, 5671-5672 # noqa: SC100
98
108
  _regex = re.compile(r"^([\w_]+)\s+(\w+)\s+([\w\-,\s]+)$")
99
109
 
110
+ @override
100
111
  def requires_command(self) -> str:
101
112
  return "semanage"
102
113
 
114
+ @override
103
115
  def command(self):
104
116
  return "semanage port -ln"
105
117
 
118
+ @override
106
119
  def process(self, output):
107
120
  labels: dict[str, dict] = defaultdict(dict)
108
121
  for line in output:
@@ -132,12 +145,15 @@ class SEPort(FactBase):
132
145
 
133
146
  default = str
134
147
 
148
+ @override
135
149
  def requires_command(self, protocol, port) -> str:
136
150
  return "sepolicy"
137
151
 
152
+ @override
138
153
  def command(self, protocol, port):
139
154
  return "(sepolicy network -p {0} 2>/dev/null || true) | grep {1}".format(port, protocol)
140
155
 
156
+ @override
141
157
  def process(self, output):
142
158
  # if type set, first line is specific and second is generic type for port range
143
159
  # each rows in the format "22: tcp ssh_port_t 22"