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,210 @@
1
+ """
2
+ Manage yum packages and repositories. Note that yum package names are case-sensitive.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from pyinfra import host, state
8
+ from pyinfra.api import operation
9
+ from pyinfra.facts.rpm import RpmPackageProvides, RpmPackages
10
+
11
+ from .util.packaging import ensure_packages, ensure_rpm, ensure_yum_repo
12
+
13
+
14
+ @operation(is_idempotent=False)
15
+ def key(src: str):
16
+ """
17
+ Add yum gpg keys with ``rpm``.
18
+
19
+ + src: filename or URL
20
+
21
+ Note:
22
+ always returns one command, not state checking
23
+
24
+ **Example:**
25
+
26
+ .. code:: python
27
+
28
+ linux_id = host.get_fact(LinuxDistribution)["release_meta"].get("ID")
29
+ yum.key(
30
+ name="Add the Docker CentOS gpg key",
31
+ src=f"https://download.docker.com/linux/{linux_id}/gpg",
32
+ )
33
+
34
+ """
35
+
36
+ yield "rpm --import {0}".format(src)
37
+
38
+
39
+ @operation()
40
+ def repo(
41
+ src: str,
42
+ present=True,
43
+ baseurl: str | None = None,
44
+ description: str | None = None,
45
+ enabled=True,
46
+ gpgcheck=True,
47
+ gpgkey: str | None = None,
48
+ ):
49
+ # NOTE: if updating this docstring also update `dnf.repo`
50
+ """
51
+ Add/remove/update yum repositories.
52
+
53
+ + src: URL or name for the ``.repo`` file
54
+ + present: whether the ``.repo`` file should be present
55
+ + baseurl: the baseurl of the repo (if ``src`` is not a URL)
56
+ + description: optional verbose description
57
+ + enabled: whether this repo is enabled
58
+ + gpgcheck: whether set ``gpgcheck=1``
59
+ + gpgkey: the URL to the gpg key for this repo
60
+
61
+ ``Baseurl``/``description``/``gpgcheck``/``gpgkey``:
62
+ These are only valid when ``src`` is a filename (ie not a URL). This is
63
+ for manual construction of repository files. Use a URL to download and
64
+ install remote repository files.
65
+
66
+ **Examples:**
67
+
68
+ .. code:: python
69
+
70
+ # Download a repository file
71
+ yum.repo(
72
+ name="Install Docker-CE repo via URL",
73
+ src="https://download.docker.com/linux/centos/docker-ce.repo",
74
+ )
75
+
76
+ # Create the repository file from baseurl/etc
77
+ yum.repo(
78
+ name="Add the Docker CentOS repo",
79
+ src="DockerCE",
80
+ baseurl="https://download.docker.com/linux/centos/7/$basearch/stable",
81
+ )
82
+ """
83
+
84
+ yield from ensure_yum_repo(
85
+ host,
86
+ src,
87
+ baseurl,
88
+ present,
89
+ description,
90
+ enabled,
91
+ gpgcheck,
92
+ gpgkey,
93
+ )
94
+
95
+
96
+ @operation()
97
+ def rpm(src: str, present=True):
98
+ # NOTE: if updating this docstring also update `dnf.rpm`
99
+ """
100
+ Add/remove ``.rpm`` file packages.
101
+
102
+ + src: filename or URL of the ``.rpm`` package
103
+ + present: whether ore not the package should exist on the system
104
+
105
+ URL sources with ``present=False``:
106
+ If the ``.rpm`` file isn't downloaded, pyinfra can't remove any existing
107
+ package as the file won't exist until mid-deploy.
108
+
109
+ **Example:**
110
+
111
+ .. code:: python
112
+
113
+ major_version = host.get_fact(LinuxDistribution)["major"]
114
+ dnf.rpm(
115
+ name="Install EPEL rpm to enable EPEL repo",
116
+ src=f"https://dl.fedoraproject.org/pub/epel/epel-release-latest-{major_version}.noarch.rpm",
117
+ )
118
+ """
119
+
120
+ yield from ensure_rpm(state, host, src, present, "yum")
121
+
122
+
123
+ @operation(is_idempotent=False)
124
+ def update():
125
+ """
126
+ Updates all yum packages.
127
+ """
128
+
129
+ yield "yum update -y"
130
+
131
+
132
+ _update = update._inner # noqa: E305 (for use below where update is a kwarg)
133
+
134
+
135
+ @operation()
136
+ def packages(
137
+ packages: str | list[str] | None = None,
138
+ present=True,
139
+ latest=False,
140
+ update=False,
141
+ clean=False,
142
+ nobest=False,
143
+ extra_install_args: str | None = None,
144
+ extra_uninstall_args: str | None = None,
145
+ ):
146
+ """
147
+ Install/remove/update yum packages & updates.
148
+
149
+ + packages: list of packages to ensure
150
+ + present: whether the packages should be installed
151
+ + latest: whether to upgrade packages without a specified version
152
+ + update: run ``yum update`` before installing packages
153
+ + clean: run ``yum clean all`` before installing packages
154
+ + nobest: add the no best option to install
155
+ + extra_install_args: additional arguments to the yum install command
156
+ + extra_uninstall_args: additional arguments to the yum uninstall command
157
+
158
+ Versions:
159
+ Package versions can be pinned as follows: ``<pkg>=<version>``
160
+
161
+ **Examples:**
162
+
163
+ .. code:: python
164
+
165
+ # Update package list and install packages
166
+ yum.packages(
167
+ name="Install Vim and Vim enhanced",
168
+ packages=["vim-enhanced", "vim"],
169
+ update=True,
170
+ )
171
+
172
+ # Install the latest versions of packages (always check)
173
+ yum.packages(
174
+ name="Install latest Vim",
175
+ packages=["vim"],
176
+ latest=True,
177
+ )
178
+ """
179
+
180
+ if clean:
181
+ yield "yum clean all"
182
+
183
+ if update:
184
+ yield from _update()
185
+
186
+ install_command = ["yum", "install", "-y"]
187
+
188
+ if nobest:
189
+ install_command.append("--nobest")
190
+
191
+ if extra_install_args:
192
+ install_command.append(extra_install_args)
193
+
194
+ uninstall_command = ["yum", "remove", "-y"]
195
+
196
+ if extra_uninstall_args:
197
+ uninstall_command.append(extra_uninstall_args)
198
+
199
+ yield from ensure_packages(
200
+ host,
201
+ packages,
202
+ host.get_fact(RpmPackages),
203
+ present,
204
+ install_command=" ".join(install_command),
205
+ uninstall_command=" ".join(uninstall_command),
206
+ upgrade_command="yum update -y",
207
+ version_join="=",
208
+ latest=latest,
209
+ expand_package_fact=lambda package: host.get_fact(RpmPackageProvides, package=package),
210
+ )
@@ -0,0 +1,175 @@
1
+ """
2
+ Manage ZFS filesystems.
3
+ """
4
+
5
+ from pyinfra import host
6
+ from pyinfra.api import operation
7
+ from pyinfra.facts.zfs import ZfsDatasets, ZfsSnapshots
8
+
9
+
10
+ @operation()
11
+ def dataset(
12
+ dataset_name,
13
+ present=True,
14
+ recursive=False,
15
+ sparse=None,
16
+ volume_size=None,
17
+ properties={},
18
+ **extra_props,
19
+ ):
20
+ """
21
+ Create, destroy or set properties on a ZFS dataset (e.g. filesystem,
22
+ volume, snapshot).
23
+
24
+ + dataset_name: name of the filesystem to operate on
25
+ + present: whether the named filesystem should exist
26
+ + recursive: whether to create parent datasets, or destroy child datasets
27
+ + sparse: for volumes, whether to create a sparse volume with no allocation
28
+ + volume_size: the size of the volume
29
+ + properties: the ZFS properties that should be set on the dataset.
30
+ + **extra_props: additional props; merged with `properties` for convenience
31
+
32
+ **Examples:**
33
+
34
+ .. code:: python
35
+
36
+ zfs.dataset(
37
+ "tank/srv",
38
+ mountpoint="/srv",
39
+ compression="lz4",
40
+ properties={"com.sun:auto_snapshot": "true"}
41
+ )
42
+ zfs.dataset("tank/vm-disks/db_srv_04", volume_size="32G") # creates a volume
43
+ zfs.dataset("tank/home@old_version", present=False)
44
+
45
+ """
46
+
47
+ noop_msg = "{0} is already {1}".format(dataset_name, "present" if present else "absent")
48
+
49
+ properties.update(extra_props)
50
+
51
+ datasets = host.get_fact(ZfsDatasets)
52
+
53
+ existing_dataset = datasets.get(dataset_name)
54
+
55
+ if present and not existing_dataset:
56
+ args = ["-o {0}={1}".format(prop, value) for prop, value in properties.items()]
57
+ if recursive:
58
+ args.append("-p")
59
+ if sparse:
60
+ args.append("-s")
61
+ if volume_size:
62
+ args.append("-V {0}".format(volume_size))
63
+
64
+ args.sort() # dicts are unordered, so make sure the test results are deterministic
65
+
66
+ yield "zfs create {0} {1}".format(" ".join(args), dataset_name)
67
+
68
+ elif present and existing_dataset:
69
+ prop_args = [
70
+ "{0}={1}".format(prop, value)
71
+ for prop, value in properties.items() - existing_dataset.items()
72
+ ]
73
+ prop_args.sort()
74
+ if prop_args:
75
+ yield "zfs set {0} {1}".format(" ".join(prop_args), dataset_name)
76
+ else:
77
+ host.noop(noop_msg)
78
+
79
+ elif existing_dataset and not present:
80
+ recursive_arg = "-r" if recursive else ""
81
+ yield "zfs destroy {0} {1}".format(recursive_arg, dataset_name)
82
+
83
+ else:
84
+ host.noop(noop_msg)
85
+
86
+
87
+ @operation()
88
+ def snapshot(snapshot_name, present=True, recursive=False, properties={}, **extra_props):
89
+ """
90
+ Create or destroy a ZFS snapshot, or modify its properties.
91
+
92
+ + dataset_name: name of the filesystem to operate on
93
+ + present: whether the named filesystem should exist
94
+ + recursive: whether to snapshot child datasets
95
+ + properties: the ZFS properties that should be set on the snapshot.
96
+ + **extra_props: additional props; merged with `properties` for convenience
97
+
98
+ **Examples:**
99
+
100
+ .. code:: python
101
+
102
+ zfs.snapshot("tank/home@weekly_backup")
103
+
104
+ """
105
+ properties.update(extra_props)
106
+ snapshots = host.get_fact(ZfsSnapshots)
107
+
108
+ if snapshot_name in snapshots or not present:
109
+ yield from dataset._inner(snapshot_name, present=present, properties=properties)
110
+
111
+ else:
112
+ args = ["-o {0}={1}".format(prop, value) for prop, value in properties.items()]
113
+ if recursive:
114
+ args.append("-r")
115
+ yield "zfs snap {0} {1}".format(" ".join(args), snapshot_name)
116
+
117
+
118
+ @operation()
119
+ def volume(
120
+ volume_name, size, sparse=False, present=True, recursive=False, properties={}, **extra_props
121
+ ):
122
+ """
123
+ Create or destroy a ZFS volume, or modify its properties.
124
+
125
+ + volume_name: name of the volume to operate on
126
+ + size: the size of the volume
127
+ + sparse: create a sparse volume
128
+ + present: whether the named volume should exist
129
+ + recursive: whether to create parent datasets or destroy child datasets
130
+ + properties: the ZFS properties that should be set on the snapshot.
131
+ + **extra_props: additional props; merged with `properties` for convenience
132
+
133
+ **Examples:**
134
+
135
+ .. code:: python
136
+
137
+ zfs.volume("tank/vm-disks/db_srv_04", "32G")
138
+
139
+ """
140
+ properties.update(extra_props)
141
+ yield from dataset._inner(
142
+ volume_name,
143
+ volume_size=size,
144
+ present=present,
145
+ sparse=sparse,
146
+ recursive=recursive,
147
+ properties=properties,
148
+ )
149
+
150
+
151
+ @operation()
152
+ def filesystem(fs_name, present=True, recursive=False, properties={}, **extra_props):
153
+ """
154
+ Create or destroy a ZFS filesystem, or modify its properties.
155
+
156
+ + fs_name: name of the volume to operate on
157
+ + present: whether the named volume should exist
158
+ + recursive: whether to create parent datasets or destroy child datasets
159
+ + properties: the ZFS properties that should be set on the snapshot.
160
+ + **extra_props: additional props; merged with `properties` for convenience
161
+
162
+ **Examples:**
163
+
164
+ .. code:: python
165
+
166
+ zfs.filesystem("tank/vm-disks/db_srv_04", "32G")
167
+
168
+ """
169
+ properties.update(extra_props)
170
+ yield from dataset._inner(
171
+ fs_name,
172
+ present=present,
173
+ recursive=recursive,
174
+ properties=properties,
175
+ )
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+
3
+ from pyinfra import host, state
4
+ from pyinfra.api import operation
5
+ from pyinfra.facts.rpm import RpmPackages
6
+
7
+ from .util.packaging import ensure_packages, ensure_rpm, ensure_yum_repo
8
+ from .yum import key as yum_key
9
+
10
+ key = yum_key
11
+
12
+
13
+ @operation()
14
+ def repo(
15
+ src,
16
+ baseurl=None,
17
+ present=True,
18
+ description=None,
19
+ enabled=True,
20
+ gpgcheck=True,
21
+ gpgkey=None,
22
+ type="rpm-md",
23
+ ):
24
+ """
25
+ Add/remove/update zypper repositories.
26
+
27
+ + src: URL or name for the ``.repo`` file
28
+ + baseurl: the baseurl of the repo (if ``name`` is not a URL)
29
+ + present: whether the ``.repo`` file should be present
30
+ + description: optional verbose description
31
+ + enabled: whether this repo is enabled
32
+ + gpgcheck: whether set ``gpgcheck=1``
33
+ + gpgkey: the URL to the gpg key for this repo
34
+ + type: the type field this repo (defaults to ``rpm-md``)
35
+
36
+ ``Baseurl``/``description``/``gpgcheck``/``gpgkey``:
37
+ These are only valid when ``name`` is a filename (ie not a URL). This is
38
+ for manual construction of repository files. Use a URL to download and
39
+ install remote repository files.
40
+
41
+ **Examples:**
42
+
43
+ .. code:: python
44
+
45
+ # Download a repository file
46
+ zypper.repo(
47
+ name="Install container virtualization repo via URL",
48
+ src="https://download.opensuse.org/repositories/Virtualization:containers/openSUSE_Tumbleweed/Virtualization:containers.repo",
49
+ )
50
+
51
+ # Create the repository file from baseurl/etc
52
+ zypper.repo(
53
+ name="Install container virtualization repo",
54
+ src=="Virtualization:containers (openSUSE_Tumbleweed)",
55
+ baseurl="https://download.opensuse.org/repositories/Virtualization:/containers/openSUSE_Tumbleweed/",
56
+ )
57
+ """
58
+
59
+ yield from ensure_yum_repo(
60
+ host,
61
+ src,
62
+ baseurl,
63
+ present,
64
+ description,
65
+ enabled,
66
+ gpgcheck,
67
+ gpgkey,
68
+ type_=type,
69
+ repo_directory="/etc/zypp/repos.d/",
70
+ )
71
+
72
+
73
+ @operation()
74
+ def rpm(src, present=True):
75
+ # NOTE: if updating this docstring also update `dnf.rpm`
76
+ """
77
+ Add/remove ``.rpm`` file packages.
78
+
79
+ + src: filename or URL of the ``.rpm`` package
80
+ + present: whether ore not the package should exist on the system
81
+
82
+ URL sources with ``present=False``:
83
+ If the ``.rpm`` file isn't downloaded, pyinfra can't remove any existing
84
+ package as the file won't exist until mid-deploy.
85
+
86
+ **Example:**
87
+
88
+ .. code:: python
89
+
90
+ zypper.rpm(
91
+ name="Install task from rpm",
92
+ src="https://github.com/go-task/task/releases/download/v2.8.1/task_linux_amd64.rpm",
93
+ )
94
+ """
95
+
96
+ yield from ensure_rpm(state, host, src, present, "zypper --non-interactive")
97
+
98
+
99
+ @operation(is_idempotent=False)
100
+ def update():
101
+ """
102
+ Updates all zypper packages.
103
+ """
104
+
105
+ yield "zypper update -y"
106
+
107
+
108
+ _update = update._inner # noqa: E305 (for use below where update is a kwarg)
109
+
110
+
111
+ @operation()
112
+ def packages(
113
+ packages: str | list[str] | None = None,
114
+ present=True,
115
+ latest=False,
116
+ update=False,
117
+ clean=False,
118
+ extra_global_install_args: str | None = None,
119
+ extra_install_args: str | None = None,
120
+ extra_global_uninstall_args: str | None = None,
121
+ extra_uninstall_args: str | None = None,
122
+ ):
123
+ """
124
+ Install/remove/update zypper packages & updates.
125
+
126
+ + packages: list of packages to ensure
127
+ + present: whether the packages should be installed
128
+ + latest: whether to upgrade packages without a specified version
129
+ + update: run ``zypper update`` before installing packages
130
+ + clean: run ``zypper clean --all`` before installing packages
131
+ + extra_global_install_args: additional global arguments to the zypper install command
132
+ + extra_install_args: additional arguments to the zypper install command
133
+ + extra_global_uninstall_args: additional global arguments to the zypper uninstall command
134
+ + extra_uninstall_args: additional arguments to the zypper uninstall command
135
+
136
+ Versions:
137
+ Package versions can be pinned like zypper: ``<pkg>=<version>``
138
+
139
+ **Examples:**
140
+
141
+ .. code:: python
142
+
143
+ # Update package list and install packages
144
+ zypper.packages(
145
+ name="Install Vim and Vim enhanced",
146
+ packages=["vim-enhanced", "vim"],
147
+ update=True,
148
+ )
149
+
150
+ # Install the latest versions of packages (always check)
151
+ zypper.packages(
152
+ name="Install latest Vim",
153
+ packages=["vim"],
154
+ latest=True,
155
+ )
156
+ """
157
+
158
+ if clean:
159
+ yield "zypper clean --all"
160
+
161
+ if update:
162
+ yield from _update()
163
+
164
+ install_command = ["zypper", "--non-interactive", "install", "-y"]
165
+
166
+ if extra_install_args:
167
+ install_command.append(extra_install_args)
168
+
169
+ if extra_global_install_args:
170
+ install_command.insert(1, extra_global_install_args)
171
+
172
+ uninstall_command = ["zypper", "--non-interactive", "remove", "-y"]
173
+
174
+ if extra_uninstall_args:
175
+ uninstall_command.append(extra_uninstall_args)
176
+
177
+ if extra_global_uninstall_args:
178
+ uninstall_command.insert(1, extra_global_uninstall_args)
179
+
180
+ upgrade_command = "zypper update -y"
181
+
182
+ yield from ensure_packages(
183
+ host,
184
+ packages,
185
+ host.get_fact(RpmPackages),
186
+ present,
187
+ install_command=" ".join(install_command),
188
+ uninstall_command=" ".join(uninstall_command),
189
+ upgrade_command=upgrade_command,
190
+ version_join="=",
191
+ latest=latest,
192
+ )