pyinfra 2.9.2__py2.py3-none-any.whl → 3.0__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 (156) hide show
  1. pyinfra/api/__init__.py +3 -0
  2. pyinfra/api/arguments.py +265 -253
  3. pyinfra/api/arguments_typed.py +80 -0
  4. pyinfra/api/command.py +68 -53
  5. pyinfra/api/config.py +139 -32
  6. pyinfra/api/connect.py +1 -1
  7. pyinfra/api/connectors.py +7 -26
  8. pyinfra/api/deploy.py +21 -52
  9. pyinfra/api/exceptions.py +33 -8
  10. pyinfra/api/facts.py +102 -137
  11. pyinfra/api/host.py +150 -82
  12. pyinfra/api/inventory.py +21 -25
  13. pyinfra/api/operation.py +240 -198
  14. pyinfra/api/operations.py +102 -148
  15. pyinfra/api/state.py +137 -79
  16. pyinfra/api/util.py +79 -86
  17. pyinfra/connectors/base.py +147 -0
  18. pyinfra/connectors/chroot.py +160 -169
  19. pyinfra/connectors/docker.py +220 -237
  20. pyinfra/connectors/dockerssh.py +231 -253
  21. pyinfra/connectors/local.py +196 -208
  22. pyinfra/connectors/ssh.py +530 -613
  23. pyinfra/connectors/ssh_util.py +114 -0
  24. pyinfra/connectors/sshuserclient/client.py +5 -3
  25. pyinfra/connectors/terraform.py +86 -65
  26. pyinfra/connectors/util.py +211 -137
  27. pyinfra/connectors/vagrant.py +60 -53
  28. pyinfra/context.py +4 -2
  29. pyinfra/facts/apk.py +2 -0
  30. pyinfra/facts/apt.py +2 -0
  31. pyinfra/facts/brew.py +2 -0
  32. pyinfra/facts/bsdinit.py +2 -0
  33. pyinfra/facts/cargo.py +2 -0
  34. pyinfra/facts/choco.py +2 -0
  35. pyinfra/facts/deb.py +7 -2
  36. pyinfra/facts/dnf.py +2 -0
  37. pyinfra/facts/docker.py +19 -0
  38. pyinfra/facts/files.py +47 -32
  39. pyinfra/facts/gem.py +2 -0
  40. pyinfra/facts/git.py +3 -1
  41. pyinfra/facts/gpg.py +3 -1
  42. pyinfra/facts/hardware.py +34 -24
  43. pyinfra/facts/iptables.py +5 -3
  44. pyinfra/facts/launchd.py +2 -0
  45. pyinfra/facts/lxd.py +2 -0
  46. pyinfra/facts/mysql.py +13 -6
  47. pyinfra/facts/npm.py +1 -0
  48. pyinfra/facts/openrc.py +2 -0
  49. pyinfra/facts/pacman.py +6 -2
  50. pyinfra/facts/pip.py +2 -0
  51. pyinfra/facts/pkg.py +2 -0
  52. pyinfra/facts/pkgin.py +2 -0
  53. pyinfra/facts/postgres.py +168 -0
  54. pyinfra/facts/postgresql.py +6 -160
  55. pyinfra/facts/rpm.py +12 -9
  56. pyinfra/facts/runit.py +68 -0
  57. pyinfra/facts/selinux.py +3 -1
  58. pyinfra/facts/server.py +80 -36
  59. pyinfra/facts/snap.py +2 -0
  60. pyinfra/facts/systemd.py +31 -12
  61. pyinfra/facts/sysvinit.py +10 -10
  62. pyinfra/facts/upstart.py +2 -0
  63. pyinfra/facts/util/packaging.py +7 -4
  64. pyinfra/facts/vzctl.py +2 -0
  65. pyinfra/facts/xbps.py +2 -0
  66. pyinfra/facts/yum.py +2 -0
  67. pyinfra/facts/zypper.py +2 -0
  68. pyinfra/local.py +4 -5
  69. pyinfra/operations/apk.py +6 -4
  70. pyinfra/operations/apt.py +46 -65
  71. pyinfra/operations/brew.py +17 -22
  72. pyinfra/operations/bsdinit.py +9 -7
  73. pyinfra/operations/cargo.py +4 -2
  74. pyinfra/operations/choco.py +4 -2
  75. pyinfra/operations/dnf.py +19 -23
  76. pyinfra/operations/docker.py +339 -0
  77. pyinfra/operations/files.py +188 -386
  78. pyinfra/operations/gem.py +4 -2
  79. pyinfra/operations/git.py +24 -53
  80. pyinfra/operations/iptables.py +29 -35
  81. pyinfra/operations/launchd.py +6 -7
  82. pyinfra/operations/lxd.py +8 -13
  83. pyinfra/operations/mysql.py +62 -81
  84. pyinfra/operations/npm.py +9 -2
  85. pyinfra/operations/openrc.py +6 -4
  86. pyinfra/operations/pacman.py +7 -8
  87. pyinfra/operations/pip.py +25 -24
  88. pyinfra/operations/pkg.py +4 -2
  89. pyinfra/operations/pkgin.py +6 -4
  90. pyinfra/operations/postgres.py +349 -0
  91. pyinfra/operations/postgresql.py +18 -379
  92. pyinfra/operations/puppet.py +3 -1
  93. pyinfra/operations/python.py +8 -19
  94. pyinfra/operations/runit.py +182 -0
  95. pyinfra/operations/selinux.py +47 -44
  96. pyinfra/operations/server.py +111 -127
  97. pyinfra/operations/snap.py +4 -4
  98. pyinfra/operations/ssh.py +20 -33
  99. pyinfra/operations/systemd.py +19 -15
  100. pyinfra/operations/sysvinit.py +9 -16
  101. pyinfra/operations/upstart.py +9 -7
  102. pyinfra/operations/util/__init__.py +12 -0
  103. pyinfra/operations/util/docker.py +177 -0
  104. pyinfra/operations/util/files.py +24 -16
  105. pyinfra/operations/util/packaging.py +55 -57
  106. pyinfra/operations/util/service.py +39 -51
  107. pyinfra/operations/vzctl.py +12 -10
  108. pyinfra/operations/xbps.py +6 -4
  109. pyinfra/operations/yum.py +18 -22
  110. pyinfra/operations/zypper.py +12 -13
  111. pyinfra/version.py +5 -2
  112. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
  113. pyinfra-3.0.dist-info/RECORD +167 -0
  114. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
  115. pyinfra-3.0.dist-info/entry_points.txt +11 -0
  116. pyinfra_cli/__main__.py +4 -3
  117. pyinfra_cli/commands.py +7 -2
  118. pyinfra_cli/exceptions.py +78 -42
  119. pyinfra_cli/inventory.py +40 -6
  120. pyinfra_cli/log.py +17 -3
  121. pyinfra_cli/main.py +133 -90
  122. pyinfra_cli/prints.py +95 -127
  123. pyinfra_cli/util.py +62 -29
  124. tests/test_api/test_api.py +2 -0
  125. tests/test_api/test_api_arguments.py +13 -13
  126. tests/test_api/test_api_deploys.py +28 -29
  127. tests/test_api/test_api_facts.py +60 -98
  128. tests/test_api/test_api_operations.py +101 -201
  129. tests/test_cli/test_cli.py +18 -49
  130. tests/test_cli/test_cli_deploy.py +11 -37
  131. tests/test_cli/test_cli_exceptions.py +50 -19
  132. tests/test_cli/util.py +1 -1
  133. tests/test_connectors/test_chroot.py +6 -6
  134. tests/test_connectors/test_docker.py +4 -4
  135. tests/test_connectors/test_dockerssh.py +38 -50
  136. tests/test_connectors/test_local.py +11 -12
  137. tests/test_connectors/test_ssh.py +105 -93
  138. tests/test_connectors/test_terraform.py +9 -15
  139. tests/test_connectors/test_util.py +24 -46
  140. tests/test_connectors/test_vagrant.py +7 -7
  141. pyinfra/api/operation.pyi +0 -117
  142. pyinfra/connectors/ansible.py +0 -171
  143. pyinfra/connectors/mech.py +0 -186
  144. pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
  145. pyinfra/connectors/winrm.py +0 -320
  146. pyinfra/facts/windows.py +0 -366
  147. pyinfra/facts/windows_files.py +0 -90
  148. pyinfra/operations/windows.py +0 -59
  149. pyinfra/operations/windows_files.py +0 -551
  150. pyinfra-2.9.2.dist-info/RECORD +0 -170
  151. pyinfra-2.9.2.dist-info/entry_points.txt +0 -14
  152. tests/test_connectors/test_ansible.py +0 -64
  153. tests/test_connectors/test_mech.py +0 -126
  154. tests/test_connectors/test_winrm.py +0 -76
  155. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
  156. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,8 @@
2
2
  Manage cargo (aka Rust) packages.
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.cargo import CargoPackages
@@ -9,8 +11,8 @@ from pyinfra.facts.cargo import CargoPackages
9
11
  from .util.packaging import ensure_packages
10
12
 
11
13
 
12
- @operation
13
- def packages(packages=None, present=True, latest=False):
14
+ @operation()
15
+ def packages(packages: str | list[str] | None = None, present=True, latest=False):
14
16
  """
15
17
  Install/remove/update cargo packages.
16
18
 
@@ -2,6 +2,8 @@
2
2
  Manage ``choco`` (Chocolatey) packages (https://chocolatey.org).
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.choco import ChocoPackages
@@ -9,8 +11,8 @@ from pyinfra.facts.choco import ChocoPackages
9
11
  from .util.packaging import ensure_packages
10
12
 
11
13
 
12
- @operation
13
- def packages(packages=None, present=True, latest=False):
14
+ @operation()
15
+ def packages(packages: str | list[str] | None = None, present=True, latest=False):
14
16
  """
15
17
  Add/remove/update ``choco`` packages.
16
18
 
pyinfra/operations/dnf.py CHANGED
@@ -2,16 +2,17 @@
2
2
  Manage dnf packages and repositories. Note that dnf package names are case-sensitive.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host, state
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.rpm import RpmPackageProvides, RpmPackages
8
10
 
9
- from . import files
10
11
  from .util.packaging import ensure_packages, ensure_rpm, ensure_yum_repo
11
12
 
12
13
 
13
14
  @operation(is_idempotent=False)
14
- def key(src):
15
+ def key(src: str):
15
16
  """
16
17
  Add dnf gpg keys with ``rpm``.
17
18
 
@@ -35,21 +36,21 @@ def key(src):
35
36
  yield "rpm --import {0}".format(src)
36
37
 
37
38
 
38
- @operation
39
+ @operation()
39
40
  def repo(
40
- src,
41
+ src: str,
41
42
  present=True,
42
- baseurl=None,
43
- description=None,
43
+ baseurl: str | None = None,
44
+ description: str | None = None,
44
45
  enabled=True,
45
46
  gpgcheck=True,
46
- gpgkey=None,
47
+ gpgkey: str | None = None,
47
48
  ):
48
49
  # NOTE: if updating this docstring also update `yum.repo`
49
50
  """
50
51
  Add/remove/update dnf repositories.
51
52
 
52
- + name: URL or name for the ``.repo`` file
53
+ + src: URL or name for the ``.repo`` file
53
54
  + present: whether the ``.repo`` file should be present
54
55
  + baseurl: the baseurl of the repo (if ``name`` is not a URL)
55
56
  + description: optional verbose description
@@ -81,9 +82,7 @@ def repo(
81
82
  """
82
83
 
83
84
  yield from ensure_yum_repo(
84
- state,
85
85
  host,
86
- files,
87
86
  src,
88
87
  baseurl,
89
88
  present,
@@ -94,8 +93,8 @@ def repo(
94
93
  )
95
94
 
96
95
 
97
- @operation
98
- def rpm(src, present=True):
96
+ @operation()
97
+ def rpm(src: str, present=True):
99
98
  # NOTE: if updating this docstring also update `yum.rpm`
100
99
  """
101
100
  Add/remove ``.rpm`` file packages.
@@ -118,7 +117,7 @@ def rpm(src, present=True):
118
117
  )
119
118
  """
120
119
 
121
- yield from ensure_rpm(state, host, files, src, present, "dnf")
120
+ yield from ensure_rpm(state, host, src, present, "dnf")
122
121
 
123
122
 
124
123
  @operation(is_idempotent=False)
@@ -130,24 +129,24 @@ def update():
130
129
  yield "dnf update -y"
131
130
 
132
131
 
133
- _update = update # noqa: E305 (for use below where update is a kwarg)
132
+ _update = update._inner # noqa: E305 (for use below where update is a kwarg)
134
133
 
135
134
 
136
- @operation
135
+ @operation()
137
136
  def packages(
138
- packages=None,
137
+ packages: str | list[str] | None = None,
139
138
  present=True,
140
139
  latest=False,
141
140
  update=False,
142
141
  clean=False,
143
142
  nobest=False,
144
- extra_install_args=None,
145
- extra_uninstall_args=None,
143
+ extra_install_args: str | None = None,
144
+ extra_uninstall_args: str | None = None,
146
145
  ):
147
146
  """
148
147
  Install/remove/update dnf packages & updates.
149
148
 
150
- + packages: list of packages to ensure
149
+ + packages: packages to ensure
151
150
  + present: whether the packages should be installed
152
151
  + latest: whether to upgrade packages without a specified version
153
152
  + update: run ``dnf update`` before installing packages
@@ -207,8 +206,5 @@ def packages(
207
206
  upgrade_command="dnf update -y",
208
207
  version_join="=",
209
208
  latest=latest,
210
- expand_package_fact=lambda package: host.get_fact(
211
- RpmPackageProvides,
212
- name=package,
213
- ),
209
+ expand_package_fact=lambda package: host.get_fact(RpmPackageProvides, package=package),
214
210
  )
@@ -0,0 +1,339 @@
1
+ """
2
+ Manager Docker Containers, Volumes and Networks
3
+ """
4
+
5
+ from pyinfra import host
6
+ from pyinfra.api import operation
7
+ from pyinfra.facts.docker import DockerContainers, DockerNetworks, DockerVolumes
8
+
9
+ from .util.docker import handle_docker
10
+
11
+
12
+ @operation()
13
+ def container(
14
+ container,
15
+ image="",
16
+ ports=None,
17
+ networks=None,
18
+ volumes=None,
19
+ env_vars=None,
20
+ pull_always=False,
21
+ present=True,
22
+ force=False,
23
+ start=True,
24
+ ):
25
+ """
26
+ Manage Docker containers
27
+
28
+ + container: name to identify the container
29
+ + image: container image and tag ex: nginx:alpine
30
+ + networks: network list to attach on container
31
+ + ports: port list to expose
32
+ + volumes: volume list to map on container
33
+ + env_vars: environment varible list to inject on container
34
+ + pull_always: force image pull
35
+ + force: remove a contaner with same name and create a new one
36
+ + present: whether the container should be up and running
37
+ + start: start or stop the container
38
+
39
+ **Examples:**
40
+
41
+ .. code:: python
42
+
43
+ # Run a container
44
+ docker.container(
45
+ name="Deploy Nginx container",
46
+ container="nginx",
47
+ image="nginx:alpine",
48
+ ports=["80:80"],
49
+ present=True,
50
+ force=True,
51
+ networks=["proxy", "services"],
52
+ volumes=["nginx_data:/usr/share/nginx/html"],
53
+ pull_always=True,
54
+ )
55
+
56
+ # Stop a container
57
+ docker.container(
58
+ name="Stop Nginx container",
59
+ container="nginx",
60
+ start=False,
61
+ )
62
+
63
+ # Start a container
64
+ docker.container(
65
+ name="Start Nginx container",
66
+ container="nginx",
67
+ start=True,
68
+ )
69
+ """
70
+
71
+ existent_container = [c for c in host.get_fact(DockerContainers) if container in c["Name"]]
72
+
73
+ if force:
74
+ if existent_container:
75
+ yield handle_docker(
76
+ resource="container",
77
+ command="remove",
78
+ container=container,
79
+ )
80
+
81
+ if present:
82
+ if not existent_container or force:
83
+ yield handle_docker(
84
+ resource="container",
85
+ command="create",
86
+ container=container,
87
+ image=image,
88
+ ports=ports,
89
+ networks=networks,
90
+ volumes=volumes,
91
+ env_vars=env_vars,
92
+ pull_always=pull_always,
93
+ present=present,
94
+ force=force,
95
+ start=start,
96
+ )
97
+
98
+ if existent_container and start:
99
+ if existent_container[0]["State"]["Status"] != "running":
100
+ yield handle_docker(
101
+ resource="container",
102
+ command="start",
103
+ container=container,
104
+ )
105
+
106
+ if existent_container and not start:
107
+ if existent_container[0]["State"]["Status"] == "running":
108
+ yield handle_docker(
109
+ resource="container",
110
+ command="stop",
111
+ container=container,
112
+ )
113
+
114
+ if existent_container and not present:
115
+ yield handle_docker(
116
+ resource="container",
117
+ command="remove",
118
+ container=container,
119
+ )
120
+
121
+
122
+ @operation(is_idempotent=False)
123
+ def image(image, present=True):
124
+ """
125
+ Manage Docker images
126
+
127
+ + image: Image and tag ex: nginx:alpine
128
+ + present: whether the Docker image should be exist
129
+
130
+ **Examples:**
131
+
132
+ .. code:: python
133
+
134
+ # Pull a Docker image
135
+ docker.image(
136
+ name="Pull nginx image",
137
+ image="nginx:alpine",
138
+ present=True,
139
+ )
140
+
141
+ # Remove a Docker image
142
+ docker.image(
143
+ name="Remove nginx image",
144
+ image:"nginx:image",
145
+ present=False,
146
+ )
147
+ """
148
+
149
+ if present:
150
+ yield handle_docker(
151
+ resource="image",
152
+ command="pull",
153
+ image=image,
154
+ )
155
+
156
+ else:
157
+ yield handle_docker(
158
+ resource="image",
159
+ command="remove",
160
+ image=image,
161
+ )
162
+
163
+
164
+ @operation()
165
+ def volume(volume, driver="", labels=None, present=True):
166
+ """
167
+ Manage Docker volumes
168
+
169
+ + volume: Volume name
170
+ + driver: Docker volume storage driver
171
+ + labels: Label list to attach in the volume
172
+ + present: whether the Docker volume should exist
173
+
174
+ **Examples:**
175
+
176
+ .. code:: python
177
+
178
+ # Create a Docker volume
179
+ docker.volume(
180
+ name="Create nginx volume",
181
+ volume="nginx_data",
182
+ present=True
183
+ )
184
+ """
185
+
186
+ existent_volume = [v for v in host.get_fact(DockerVolumes) if v["Name"] == volume]
187
+
188
+ if present:
189
+
190
+ if existent_volume:
191
+ host.noop("Volume alredy exist!")
192
+ return
193
+
194
+ yield handle_docker(
195
+ resource="volume",
196
+ command="create",
197
+ volume=volume,
198
+ driver=driver,
199
+ labels=labels,
200
+ present=present,
201
+ )
202
+
203
+ else:
204
+ if existent_volume is None:
205
+ host.noop("There is no {0} volume!".format(volume))
206
+ return
207
+
208
+ yield handle_docker(
209
+ resource="volume",
210
+ command="remove",
211
+ volume=volume,
212
+ )
213
+
214
+
215
+ @operation()
216
+ def network(
217
+ network,
218
+ driver="",
219
+ gateway="",
220
+ ip_range="",
221
+ ipam_driver="",
222
+ subnet="",
223
+ scope="",
224
+ opts=None,
225
+ ipam_opts=None,
226
+ labels=None,
227
+ ingress=False,
228
+ attachable=False,
229
+ present=True,
230
+ ):
231
+ """
232
+ Manage docker networks
233
+
234
+ + network_name: Image name
235
+ + driver: Container image and tag ex: nginx:alpine
236
+ + gateway: IPv4 or IPv6 Gateway for the master subnet
237
+ + ip_range: Allocate container ip from a sub-range
238
+ + ipam_driver: IP Address Management Driver
239
+ + subnet: Subnet in CIDR format that represents a network segment
240
+ + scope: Control the network's scope
241
+ + opts: Set driver specific options
242
+ + ipam_opts: Set IPAM driver specific options
243
+ + labels: Label list to attach in the network
244
+ + ingress: Create swarm routing-mesh network
245
+ + attachable: Enable manual container attachment
246
+ + present: whether the Docker network should exist
247
+
248
+ **Examples:**
249
+
250
+ .. code:: python
251
+
252
+ # Create Docker network
253
+ docker.network(
254
+ name="Create nginx network",
255
+ network_name="nginx",
256
+ attachable=True,
257
+ present=True,
258
+ )
259
+ """
260
+ existent_network = [n for n in host.get_fact(DockerNetworks) if n["Name"] == network]
261
+
262
+ if present:
263
+ if existent_network:
264
+ host.noop("Alredy exist a network with {0} name!".format(network))
265
+ return
266
+
267
+ yield handle_docker(
268
+ resource="network",
269
+ command="create",
270
+ network=network,
271
+ driver=driver,
272
+ gateway=gateway,
273
+ ip_range=ip_range,
274
+ ipam_driver=ipam_driver,
275
+ subnet=subnet,
276
+ scope=scope,
277
+ opts=opts,
278
+ ipam_opts=ipam_opts,
279
+ labels=labels,
280
+ ingress=ingress,
281
+ attachable=attachable,
282
+ present=present,
283
+ )
284
+
285
+ else:
286
+ if existent_network is None:
287
+ host.noop("Ther is not network with {0} name!".format(network))
288
+ return
289
+
290
+ yield handle_docker(
291
+ resource="network",
292
+ command="create",
293
+ network=network,
294
+ )
295
+
296
+
297
+ @operation(is_idempotent=False)
298
+ def prune(
299
+ all=False,
300
+ volume=False,
301
+ filter="",
302
+ ):
303
+ """
304
+ Execute a docker system prune.
305
+
306
+ + all: Remove all unused images not just dangling ones
307
+ + volumes: Prune anonymous volumes
308
+ + filter: Provide filter values (e.g. "label=<key>=<value>" or "until=24h")
309
+
310
+ **Examples:**
311
+
312
+ .. code:: python
313
+
314
+ # Remove dangling images
315
+ docker.prune(
316
+ name="remove dangling images",
317
+ )
318
+
319
+ # Remove all images and volumes
320
+ docker.prune(
321
+ name="Remove all images and volumes",
322
+ all=True,
323
+ volumes=True,
324
+ )
325
+
326
+ # Remove images older than 90 days
327
+ docker.prune(
328
+ name="Remove unused older than 90 days",
329
+ filter="until=2160h"
330
+ )
331
+ """
332
+
333
+ yield handle_docker(
334
+ resource="system",
335
+ command="prune",
336
+ all=all,
337
+ volume=volume,
338
+ filter=filter,
339
+ )