pyinfra 0.11.dev3__py3-none-any.whl → 3.5.1__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 (203) hide show
  1. pyinfra/__init__.py +9 -12
  2. pyinfra/__main__.py +4 -0
  3. pyinfra/api/__init__.py +18 -3
  4. pyinfra/api/arguments.py +406 -0
  5. pyinfra/api/arguments_typed.py +79 -0
  6. pyinfra/api/command.py +274 -0
  7. pyinfra/api/config.py +222 -28
  8. pyinfra/api/connect.py +33 -13
  9. pyinfra/api/connectors.py +27 -0
  10. pyinfra/api/deploy.py +65 -66
  11. pyinfra/api/exceptions.py +67 -18
  12. pyinfra/api/facts.py +253 -202
  13. pyinfra/api/host.py +413 -50
  14. pyinfra/api/inventory.py +121 -160
  15. pyinfra/api/operation.py +432 -262
  16. pyinfra/api/operations.py +273 -260
  17. pyinfra/api/state.py +302 -248
  18. pyinfra/api/util.py +291 -368
  19. pyinfra/connectors/base.py +173 -0
  20. pyinfra/connectors/chroot.py +212 -0
  21. pyinfra/connectors/docker.py +381 -0
  22. pyinfra/connectors/dockerssh.py +297 -0
  23. pyinfra/connectors/local.py +238 -0
  24. pyinfra/connectors/scp/__init__.py +1 -0
  25. pyinfra/connectors/scp/client.py +204 -0
  26. pyinfra/connectors/ssh.py +670 -0
  27. pyinfra/connectors/ssh_util.py +114 -0
  28. pyinfra/connectors/sshuserclient/client.py +309 -0
  29. pyinfra/connectors/sshuserclient/config.py +102 -0
  30. pyinfra/connectors/terraform.py +135 -0
  31. pyinfra/connectors/util.py +410 -0
  32. pyinfra/connectors/vagrant.py +183 -0
  33. pyinfra/context.py +145 -0
  34. pyinfra/facts/__init__.py +7 -6
  35. pyinfra/facts/apk.py +22 -7
  36. pyinfra/facts/apt.py +117 -60
  37. pyinfra/facts/brew.py +100 -15
  38. pyinfra/facts/bsdinit.py +23 -0
  39. pyinfra/facts/cargo.py +37 -0
  40. pyinfra/facts/choco.py +47 -0
  41. pyinfra/facts/crontab.py +195 -0
  42. pyinfra/facts/deb.py +94 -0
  43. pyinfra/facts/dnf.py +48 -0
  44. pyinfra/facts/docker.py +96 -23
  45. pyinfra/facts/efibootmgr.py +113 -0
  46. pyinfra/facts/files.py +630 -58
  47. pyinfra/facts/flatpak.py +77 -0
  48. pyinfra/facts/freebsd.py +70 -0
  49. pyinfra/facts/gem.py +19 -6
  50. pyinfra/facts/git.py +59 -14
  51. pyinfra/facts/gpg.py +150 -0
  52. pyinfra/facts/hardware.py +313 -167
  53. pyinfra/facts/iptables.py +72 -62
  54. pyinfra/facts/launchd.py +44 -0
  55. pyinfra/facts/lxd.py +17 -4
  56. pyinfra/facts/mysql.py +122 -86
  57. pyinfra/facts/npm.py +17 -9
  58. pyinfra/facts/openrc.py +71 -0
  59. pyinfra/facts/opkg.py +246 -0
  60. pyinfra/facts/pacman.py +50 -7
  61. pyinfra/facts/pip.py +24 -7
  62. pyinfra/facts/pipx.py +82 -0
  63. pyinfra/facts/pkg.py +15 -6
  64. pyinfra/facts/pkgin.py +35 -0
  65. pyinfra/facts/podman.py +54 -0
  66. pyinfra/facts/postgres.py +178 -0
  67. pyinfra/facts/postgresql.py +6 -147
  68. pyinfra/facts/rpm.py +105 -0
  69. pyinfra/facts/runit.py +77 -0
  70. pyinfra/facts/selinux.py +161 -0
  71. pyinfra/facts/server.py +746 -285
  72. pyinfra/facts/snap.py +88 -0
  73. pyinfra/facts/systemd.py +139 -0
  74. pyinfra/facts/sysvinit.py +59 -0
  75. pyinfra/facts/upstart.py +35 -0
  76. pyinfra/facts/util/__init__.py +17 -0
  77. pyinfra/facts/util/databases.py +4 -6
  78. pyinfra/facts/util/packaging.py +37 -6
  79. pyinfra/facts/util/units.py +30 -0
  80. pyinfra/facts/util/win_files.py +99 -0
  81. pyinfra/facts/vzctl.py +20 -13
  82. pyinfra/facts/xbps.py +35 -0
  83. pyinfra/facts/yum.py +34 -40
  84. pyinfra/facts/zfs.py +77 -0
  85. pyinfra/facts/zypper.py +42 -0
  86. pyinfra/local.py +45 -83
  87. pyinfra/operations/__init__.py +12 -0
  88. pyinfra/operations/apk.py +98 -0
  89. pyinfra/operations/apt.py +488 -0
  90. pyinfra/operations/brew.py +231 -0
  91. pyinfra/operations/bsdinit.py +59 -0
  92. pyinfra/operations/cargo.py +45 -0
  93. pyinfra/operations/choco.py +61 -0
  94. pyinfra/operations/crontab.py +191 -0
  95. pyinfra/operations/dnf.py +210 -0
  96. pyinfra/operations/docker.py +446 -0
  97. pyinfra/operations/files.py +1939 -0
  98. pyinfra/operations/flatpak.py +94 -0
  99. pyinfra/operations/freebsd/__init__.py +12 -0
  100. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  101. pyinfra/operations/freebsd/pkg.py +219 -0
  102. pyinfra/operations/freebsd/service.py +116 -0
  103. pyinfra/operations/freebsd/sysrc.py +92 -0
  104. pyinfra/operations/gem.py +47 -0
  105. pyinfra/operations/git.py +419 -0
  106. pyinfra/operations/iptables.py +311 -0
  107. pyinfra/operations/launchd.py +45 -0
  108. pyinfra/operations/lxd.py +68 -0
  109. pyinfra/operations/mysql.py +609 -0
  110. pyinfra/operations/npm.py +57 -0
  111. pyinfra/operations/openrc.py +63 -0
  112. pyinfra/operations/opkg.py +88 -0
  113. pyinfra/operations/pacman.py +81 -0
  114. pyinfra/operations/pip.py +205 -0
  115. pyinfra/operations/pipx.py +102 -0
  116. pyinfra/operations/pkg.py +70 -0
  117. pyinfra/operations/pkgin.py +91 -0
  118. pyinfra/operations/postgres.py +436 -0
  119. pyinfra/operations/postgresql.py +30 -0
  120. pyinfra/operations/puppet.py +40 -0
  121. pyinfra/operations/python.py +72 -0
  122. pyinfra/operations/runit.py +184 -0
  123. pyinfra/operations/selinux.py +189 -0
  124. pyinfra/operations/server.py +1099 -0
  125. pyinfra/operations/snap.py +117 -0
  126. pyinfra/operations/ssh.py +216 -0
  127. pyinfra/operations/systemd.py +149 -0
  128. pyinfra/operations/sysvinit.py +141 -0
  129. pyinfra/operations/upstart.py +68 -0
  130. pyinfra/operations/util/__init__.py +12 -0
  131. pyinfra/operations/util/docker.py +251 -0
  132. pyinfra/operations/util/files.py +247 -0
  133. pyinfra/operations/util/packaging.py +336 -0
  134. pyinfra/operations/util/service.py +46 -0
  135. pyinfra/operations/vzctl.py +137 -0
  136. pyinfra/operations/xbps.py +77 -0
  137. pyinfra/operations/yum.py +210 -0
  138. pyinfra/operations/zfs.py +175 -0
  139. pyinfra/operations/zypper.py +192 -0
  140. pyinfra/progress.py +44 -32
  141. pyinfra/py.typed +0 -0
  142. pyinfra/version.py +9 -1
  143. pyinfra-3.5.1.dist-info/METADATA +141 -0
  144. pyinfra-3.5.1.dist-info/RECORD +159 -0
  145. {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info}/WHEEL +1 -2
  146. pyinfra-3.5.1.dist-info/entry_points.txt +12 -0
  147. {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info/licenses}/LICENSE.md +1 -1
  148. pyinfra_cli/__init__.py +1 -0
  149. pyinfra_cli/cli.py +780 -0
  150. pyinfra_cli/commands.py +66 -0
  151. pyinfra_cli/exceptions.py +155 -65
  152. pyinfra_cli/inventory.py +233 -89
  153. pyinfra_cli/log.py +39 -43
  154. pyinfra_cli/main.py +26 -495
  155. pyinfra_cli/prints.py +215 -156
  156. pyinfra_cli/util.py +172 -105
  157. pyinfra_cli/virtualenv.py +25 -20
  158. pyinfra/api/connectors/__init__.py +0 -21
  159. pyinfra/api/connectors/ansible.py +0 -99
  160. pyinfra/api/connectors/docker.py +0 -178
  161. pyinfra/api/connectors/local.py +0 -169
  162. pyinfra/api/connectors/ssh.py +0 -402
  163. pyinfra/api/connectors/sshuserclient/client.py +0 -105
  164. pyinfra/api/connectors/sshuserclient/config.py +0 -90
  165. pyinfra/api/connectors/util.py +0 -63
  166. pyinfra/api/connectors/vagrant.py +0 -155
  167. pyinfra/facts/init.py +0 -176
  168. pyinfra/facts/util/files.py +0 -102
  169. pyinfra/hook.py +0 -41
  170. pyinfra/modules/__init__.py +0 -11
  171. pyinfra/modules/apk.py +0 -64
  172. pyinfra/modules/apt.py +0 -272
  173. pyinfra/modules/brew.py +0 -122
  174. pyinfra/modules/files.py +0 -711
  175. pyinfra/modules/gem.py +0 -30
  176. pyinfra/modules/git.py +0 -115
  177. pyinfra/modules/init.py +0 -344
  178. pyinfra/modules/iptables.py +0 -271
  179. pyinfra/modules/lxd.py +0 -45
  180. pyinfra/modules/mysql.py +0 -347
  181. pyinfra/modules/npm.py +0 -47
  182. pyinfra/modules/pacman.py +0 -60
  183. pyinfra/modules/pip.py +0 -99
  184. pyinfra/modules/pkg.py +0 -43
  185. pyinfra/modules/postgresql.py +0 -245
  186. pyinfra/modules/puppet.py +0 -20
  187. pyinfra/modules/python.py +0 -37
  188. pyinfra/modules/server.py +0 -524
  189. pyinfra/modules/ssh.py +0 -150
  190. pyinfra/modules/util/files.py +0 -52
  191. pyinfra/modules/util/packaging.py +0 -118
  192. pyinfra/modules/vzctl.py +0 -133
  193. pyinfra/modules/yum.py +0 -171
  194. pyinfra/pseudo_modules.py +0 -64
  195. pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
  196. pyinfra-0.11.dev3.dist-info/METADATA +0 -135
  197. pyinfra-0.11.dev3.dist-info/RECORD +0 -95
  198. pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
  199. pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
  200. pyinfra_cli/__main__.py +0 -40
  201. pyinfra_cli/config.py +0 -92
  202. /pyinfra/{modules/util → connectors}/__init__.py +0 -0
  203. /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
@@ -0,0 +1,184 @@
1
+ """
2
+ Manage runit services.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Optional
8
+
9
+ from pyinfra import host
10
+ from pyinfra.api import operation
11
+ from pyinfra.facts.files import File
12
+ from pyinfra.facts.runit import RunitManaged, RunitStatus
13
+
14
+ from .files import file, link
15
+ from .util.service import handle_service_control
16
+
17
+
18
+ @operation()
19
+ def service(
20
+ service: str,
21
+ running: bool = True,
22
+ restarted: bool = False,
23
+ reloaded: bool = False,
24
+ command: Optional[str] = None,
25
+ enabled: Optional[bool] = None,
26
+ managed: bool = True,
27
+ svdir: str = "/var/service",
28
+ sourcedir: str = "/etc/sv",
29
+ ):
30
+ """
31
+ Manage the state of runit services.
32
+
33
+ + service: name of the service to manage
34
+ + running: whether the service should be running
35
+ + restarted: whether the service should be restarted
36
+ + reloaded: whether the service should be reloaded
37
+ + command: custom command to pass like: ``sv <command> <service>``
38
+ + enabled: whether this service should be enabled/disabled on boot
39
+ + managed: whether runit should manage this service
40
+
41
+ For services to be controlled, they first need to be managed by runit by
42
+ adding a symlink to the service in ``SVDIR``.
43
+ By setting ``managed=False`` the symlink will be removed.
44
+ Other options won't have any effect after that.
45
+ Although the ``<service>/down`` file can still be controlled with the
46
+ ``enabled`` option.
47
+
48
+ + svdir: alternative ``SVDIR``
49
+
50
+ An alternative ``SVDIR`` can be specified. This can be used for user services.
51
+
52
+ + sourcedir: where to search for available services
53
+
54
+ An alternative directory for available services can be specified.
55
+ Example: ``sourcedir=/etc/sv.local`` for services managed by the administrator.
56
+ """
57
+
58
+ was_managed = service in host.get_fact(RunitManaged, service=service, svdir=svdir)
59
+ was_auto = not host.get_fact(File, path="{0}/{1}/down".format(sourcedir, service))
60
+
61
+ # Disable autostart for previously unmanaged services.
62
+ #
63
+ # Where ``running=False`` is requested, this prevents one case of briefly
64
+ # starting and stopping the service.
65
+ if not was_managed and managed and was_auto:
66
+ yield from auto._inner(
67
+ service=service,
68
+ auto=False,
69
+ sourcedir=sourcedir,
70
+ )
71
+
72
+ yield from manage._inner(
73
+ service=service,
74
+ managed=managed,
75
+ svdir=svdir,
76
+ sourcedir=sourcedir,
77
+ )
78
+
79
+ # Service wasn't managed before, so wait for ``runsv`` to start.
80
+ # ``runsvdir`` will check at least every 5 seconds for new services.
81
+ # Wait for at most 10 seconds for the service to be managed, otherwise fail.
82
+ if not was_managed and managed:
83
+ yield from wait_runsv._inner(
84
+ service=service,
85
+ svdir=svdir,
86
+ )
87
+
88
+ if isinstance(enabled, bool):
89
+ yield from auto._inner(
90
+ service=service,
91
+ auto=enabled,
92
+ sourcedir=sourcedir,
93
+ )
94
+ else:
95
+ # restore previous state of ``<service>/down``
96
+ yield from auto._inner(
97
+ service=service,
98
+ auto=was_auto,
99
+ sourcedir=sourcedir,
100
+ )
101
+
102
+ # Services need to be managed by ``runit`` for the other options to make sense.
103
+ if not managed:
104
+ return
105
+
106
+ yield from handle_service_control(
107
+ host,
108
+ service,
109
+ host.get_fact(RunitStatus, service=service, svdir=svdir),
110
+ "SVDIR={0} sv {{1}} {{0}}".format(svdir),
111
+ running,
112
+ restarted,
113
+ reloaded,
114
+ command,
115
+ )
116
+
117
+
118
+ @operation()
119
+ def manage(
120
+ service: str,
121
+ managed: bool = True,
122
+ svdir: str = "/var/service",
123
+ sourcedir: str = "/etc/sv",
124
+ ):
125
+ """
126
+ Manage runit svdir links.
127
+
128
+ + service: name of the service to manage
129
+ + managed: whether the link should exist
130
+ + svdir: alternative ``SVDIR``
131
+ + sourcedir: where to search for available services
132
+ """
133
+
134
+ yield from link._inner(
135
+ path="{0}/{1}".format(svdir, service),
136
+ target="{0}/{1}".format(sourcedir, service),
137
+ present=managed,
138
+ create_remote_dir=False,
139
+ )
140
+
141
+
142
+ @operation(is_idempotent=False)
143
+ def wait_runsv(
144
+ service: str,
145
+ svdir: str = "/var/service",
146
+ timeout: int = 10,
147
+ ):
148
+ """
149
+ Wait for runsv for ``service`` to be available.
150
+
151
+ + service: name of the service to manage
152
+ + svdir: alternative ``SVDIR``
153
+ + timeout: time in seconds to wait
154
+ """
155
+
156
+ yield (
157
+ "export SVDIR={0}\n"
158
+ "for i in $(seq {1}); do\n"
159
+ " sv status {2} > /dev/null && exit 0\n"
160
+ " sleep 1;\n"
161
+ "done\n"
162
+ "exit 1"
163
+ ).format(svdir, timeout, service)
164
+
165
+
166
+ @operation()
167
+ def auto(
168
+ service: str,
169
+ auto: bool = True,
170
+ sourcedir: str = "/etc/sv",
171
+ ):
172
+ """
173
+ Start service automatically by managing the ``service/down`` file.
174
+
175
+ + service: name of the service to manage
176
+ + auto: whether the service should start automatically
177
+ + sourcedir: where to search for available services
178
+ """
179
+
180
+ yield from file._inner(
181
+ path="{0}/{1}/down".format(sourcedir, service),
182
+ present=not auto,
183
+ create_remote_dir=False,
184
+ )
@@ -0,0 +1,189 @@
1
+ """
2
+ Provides operations to set SELinux file contexts, booleans and port types.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+
9
+ from pyinfra import host
10
+ from pyinfra.api import OperationValueError, QuoteString, StringCommand, operation
11
+ from pyinfra.facts.selinux import FileContext, FileContextMapping, SEBoolean, SEPort, SEPorts
12
+ from pyinfra.facts.server import Which
13
+
14
+
15
+ class Boolean(Enum):
16
+ ON = "on"
17
+ OFF = "off"
18
+
19
+
20
+ class Protocol(Enum):
21
+ UDP = "udp"
22
+ TCP = "tcp"
23
+ SCTP = "sctp"
24
+ DCCP = "dccp"
25
+
26
+
27
+ @operation()
28
+ def boolean(bool_name: str, value: Boolean, persistent=False):
29
+ """
30
+ Set the specified SELinux boolean to the desired state.
31
+
32
+ + boolean: name of an SELinux boolean
33
+ + value: desired state of the boolean
34
+ + persistent: whether to write updated policy or not
35
+
36
+ Note: This operation requires root privileges.
37
+
38
+ **Example:**
39
+
40
+ .. code:: python
41
+
42
+ selinux.boolean(
43
+ name='Allow Apache to connect to LDAP server',
44
+ 'httpd_can_network_connect',
45
+ Boolean.ON,
46
+ persistent=True
47
+ )
48
+ """
49
+
50
+ value_str: str
51
+ if value in ["on", "off"]: # compatibility with the old version
52
+ assert isinstance(value, str)
53
+ value_str = value
54
+ elif value is Boolean.ON:
55
+ value_str = "on"
56
+ elif value is Boolean.OFF:
57
+ value_str = "off"
58
+ else:
59
+ raise OperationValueError(f"Invalid value '{value}' for boolean operation")
60
+
61
+ if host.get_fact(SEBoolean, boolean=bool_name) != value_str:
62
+ persist = "-P " if persistent else ""
63
+ yield StringCommand("setsebool", f"{persist}{bool_name}", value_str)
64
+ else:
65
+ host.noop(f"boolean '{bool_name}' already had the value '{value_str}'")
66
+
67
+
68
+ @operation()
69
+ def file_context(path: str, se_type: str):
70
+ """
71
+ Set the SELinux type for the specified path to the specified value.
72
+
73
+ + path: the target path (expression) for the context
74
+ + se_type: the SELinux type for the given target
75
+
76
+ **Example:**
77
+
78
+ .. code:: python
79
+
80
+ selinux.file_context(
81
+ name='Allow /foo/bar to be served by the web server',
82
+ '/foo/bar',
83
+ 'httpd_sys_content_t'
84
+ )
85
+ """
86
+
87
+ current = host.get_fact(FileContext, path=path) or {}
88
+ if se_type != current.get("type", ""):
89
+ yield StringCommand("chcon", "-t", se_type, QuoteString(path))
90
+ else:
91
+ host.noop(f"file_context: '{path}' already had type '{se_type}'")
92
+
93
+
94
+ @operation()
95
+ def file_context_mapping(target: str, se_type: str | None = None, present=True):
96
+ """
97
+ Set the SELinux file context mapping for paths matching the target.
98
+
99
+ + target: the target path (expression) for the context
100
+ + se_type: the SELinux type for the given target
101
+ + present: whether to add or remove the target -> context mapping
102
+
103
+ Note: `file_context` does not change the SELinux file context for existing files
104
+ so `restorecon` may need to be run manually if the file contexts cannot be created
105
+ before the related files.
106
+
107
+ **Example:**
108
+
109
+ .. code:: python
110
+
111
+ selinux.file_context_mapping(
112
+ name='Allow Apache to serve content from the /web directory',
113
+ r'/web(/.*)?',
114
+ se_type='httpd_sys_content_t'
115
+ )
116
+ """
117
+ if present and (se_type is None):
118
+ raise ValueError("se_type must have a valid value if present is set")
119
+
120
+ current = host.get_fact(FileContextMapping, target=target)
121
+ if present:
122
+ option = "-a" if len(current) == 0 else ("-m" if current.get("type") != se_type else "")
123
+ if option != "":
124
+ yield StringCommand("semanage", "fcontext", option, "-t", se_type, QuoteString(target))
125
+ else:
126
+ host.noop(f"mapping for '{target}' -> '{se_type}' already present")
127
+ else:
128
+ if len(current) > 0:
129
+ yield StringCommand("semanage", "fcontext", "-d", QuoteString(target))
130
+ else:
131
+ host.noop(f"no existing mapping for '{target}'")
132
+
133
+
134
+ @operation()
135
+ def port(protocol: Protocol | str, port_num: int, se_type: str | None = None, present=True):
136
+ """
137
+ Set the SELinux type for the specified protocol and port.
138
+
139
+ + protocol: the protocol: (udp|tcp|sctp|dccp)
140
+ + port: the port
141
+ + se_type: the SELinux type for the given port
142
+ + present: whether to add or remove the SELinux type for the port
143
+
144
+ Note: This operation requires root privileges.
145
+
146
+ **Example:**
147
+
148
+ .. code:: python
149
+
150
+ selinux.port(
151
+ name='Allow Apache to provide service on port 2222',
152
+ Protocol.TCP,
153
+ 2222,
154
+ 'http_port_t',
155
+ )
156
+ """
157
+
158
+ if protocol is Protocol:
159
+ assert isinstance(protocol, Protocol)
160
+ protocol = protocol.value
161
+
162
+ if present and (se_type is None):
163
+ raise ValueError("se_type must have a valid value if present is set")
164
+
165
+ new_type = se_type if present else ""
166
+ direct_get = len(host.get_fact(Which, command="sepolicy") or "") > 0
167
+ if direct_get:
168
+ current = host.get_fact(SEPort, protocol=protocol, port=port_num)
169
+ else:
170
+ port_info = host.get_fact(SEPorts)
171
+ current = port_info.get(protocol, {}).get(str(port_num), "")
172
+
173
+ if present:
174
+ option = "-a" if current == "" else ("-m" if current != se_type else "")
175
+ if option != "":
176
+ yield StringCommand("semanage", "port", option, "-t", se_type, "-p", protocol, port_num)
177
+ else:
178
+ host.noop(f"setype for '{protocol}/{port_num}' is already '{se_type}'")
179
+ else:
180
+ if current != "":
181
+ yield StringCommand("semanage", "port", "-d", "-p", protocol, port_num)
182
+ else:
183
+ host.noop(f"setype for '{protocol}/{port_num}' is already unset")
184
+
185
+ if (present and (option != "")) or (not present and (current != "")):
186
+ if not direct_get:
187
+ if protocol not in port_info:
188
+ port_info[protocol] = {}
189
+ port_info[protocol][str(port_num)] = new_type