pyinfra 3.5.1__py3-none-any.whl → 3.6__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.
- pyinfra/api/__init__.py +1 -0
- pyinfra/api/arguments.py +7 -0
- pyinfra/api/exceptions.py +6 -0
- pyinfra/api/facts.py +17 -1
- pyinfra/api/host.py +3 -0
- pyinfra/api/metadata.py +69 -0
- pyinfra/api/operations.py +3 -3
- pyinfra/api/util.py +22 -5
- pyinfra/connectors/docker.py +25 -1
- pyinfra/connectors/ssh.py +57 -0
- pyinfra/connectors/util.py +16 -9
- pyinfra/facts/crontab.py +7 -7
- pyinfra/facts/files.py +1 -2
- pyinfra/facts/npm.py +1 -1
- pyinfra/facts/server.py +18 -2
- pyinfra/operations/apk.py +2 -1
- pyinfra/operations/apt.py +15 -7
- pyinfra/operations/brew.py +1 -0
- pyinfra/operations/crontab.py +4 -1
- pyinfra/operations/dnf.py +4 -1
- pyinfra/operations/docker.py +62 -16
- pyinfra/operations/files.py +87 -12
- pyinfra/operations/flatpak.py +1 -0
- pyinfra/operations/gem.py +1 -0
- pyinfra/operations/git.py +1 -0
- pyinfra/operations/iptables.py +1 -0
- pyinfra/operations/lxd.py +1 -0
- pyinfra/operations/mysql.py +1 -0
- pyinfra/operations/opkg.py +2 -1
- pyinfra/operations/pacman.py +1 -0
- pyinfra/operations/pip.py +1 -0
- pyinfra/operations/pipx.py +1 -0
- pyinfra/operations/pkg.py +1 -0
- pyinfra/operations/pkgin.py +1 -0
- pyinfra/operations/postgres.py +1 -0
- pyinfra/operations/puppet.py +1 -0
- pyinfra/operations/python.py +1 -0
- pyinfra/operations/selinux.py +1 -0
- pyinfra/operations/server.py +1 -0
- pyinfra/operations/snap.py +2 -1
- pyinfra/operations/ssh.py +1 -0
- pyinfra/operations/systemd.py +1 -0
- pyinfra/operations/sysvinit.py +2 -1
- pyinfra/operations/util/docker.py +164 -8
- pyinfra/operations/util/packaging.py +2 -0
- pyinfra/operations/xbps.py +1 -0
- pyinfra/operations/yum.py +4 -1
- pyinfra/operations/zfs.py +1 -0
- pyinfra/operations/zypper.py +1 -0
- {pyinfra-3.5.1.dist-info → pyinfra-3.6.dist-info}/METADATA +2 -1
- {pyinfra-3.5.1.dist-info → pyinfra-3.6.dist-info}/RECORD +55 -54
- {pyinfra-3.5.1.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -1
- pyinfra_cli/cli.py +13 -0
- {pyinfra-3.5.1.dist-info → pyinfra-3.6.dist-info}/entry_points.txt +0 -0
- {pyinfra-3.5.1.dist-info → pyinfra-3.6.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -1,16 +1,169 @@
|
|
|
1
|
-
import
|
|
2
|
-
from typing import Any
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
from pyinfra.api import OperationError
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
@
|
|
7
|
+
@dataclass
|
|
8
|
+
class ImageReference:
|
|
9
|
+
"""Represents a parsed Docker image reference."""
|
|
10
|
+
|
|
11
|
+
repository: str
|
|
12
|
+
namespace: str | None = None
|
|
13
|
+
tag: str | None = None
|
|
14
|
+
digest: str | None = None
|
|
15
|
+
registry_host: str | None = None
|
|
16
|
+
registry_port: int | None = None
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def registry(self) -> str | None:
|
|
20
|
+
"""Get the full registry address (host:port)."""
|
|
21
|
+
if not self.registry_host:
|
|
22
|
+
return None
|
|
23
|
+
if self.registry_port:
|
|
24
|
+
return f"{self.registry_host}:{self.registry_port}"
|
|
25
|
+
return self.registry_host
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def name(self) -> str:
|
|
29
|
+
"""Get the full image name without tag or digest."""
|
|
30
|
+
parts = []
|
|
31
|
+
if self.registry:
|
|
32
|
+
parts.append(self.registry)
|
|
33
|
+
if self.namespace:
|
|
34
|
+
parts.append(self.namespace)
|
|
35
|
+
parts.append(self.repository)
|
|
36
|
+
return "/".join(parts)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def full_reference(self) -> str:
|
|
40
|
+
"""Get the complete image reference string."""
|
|
41
|
+
ref = self.name
|
|
42
|
+
if self.tag:
|
|
43
|
+
ref += f":{self.tag}"
|
|
44
|
+
if self.digest:
|
|
45
|
+
ref += f"@{self.digest}"
|
|
46
|
+
return ref
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parse_registry(registry: str) -> tuple[str, int | None]:
|
|
50
|
+
"""
|
|
51
|
+
Parse a registry string into host and port components.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
registry: String like "registry.io:5000" or "registry.io"
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
tuple: (host, port) where port is None if not specified
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
ValueError: If port is specified but not a valid integer
|
|
61
|
+
"""
|
|
62
|
+
if ":" in registry:
|
|
63
|
+
host, port_str = registry.rsplit(":", 1)
|
|
64
|
+
if port_str: # Only try to parse if port_str is not empty
|
|
65
|
+
try:
|
|
66
|
+
port = int(port_str)
|
|
67
|
+
if port < 0 or port > 65535:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"Invalid port number: {port}. Port must be between 0 and 65535"
|
|
70
|
+
)
|
|
71
|
+
return host, port
|
|
72
|
+
except ValueError as e:
|
|
73
|
+
if "invalid literal" in str(e):
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"Invalid port in registry '{registry}': '{port_str}' is not a valid port number"
|
|
76
|
+
)
|
|
77
|
+
raise # Re-raise port range error
|
|
78
|
+
else:
|
|
79
|
+
# Empty port (e.g., "registry.io:")
|
|
80
|
+
raise ValueError(f"Invalid registry format '{registry}': port cannot be empty")
|
|
81
|
+
else:
|
|
82
|
+
return registry, None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def parse_image_reference(image: str) -> ImageReference:
|
|
86
|
+
"""
|
|
87
|
+
Parse a Docker image reference into components.
|
|
88
|
+
|
|
89
|
+
Format: [HOST[:PORT]/]NAMESPACE/REPOSITORY[:TAG][@DIGEST]
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
ValueError: If the image reference is empty or invalid
|
|
93
|
+
"""
|
|
94
|
+
if not image or not image.strip():
|
|
95
|
+
raise ValueError("Image reference cannot be empty")
|
|
96
|
+
|
|
97
|
+
original = image.strip()
|
|
98
|
+
registry_host = None
|
|
99
|
+
registry_port = None
|
|
100
|
+
namespace = None
|
|
101
|
+
repository = None
|
|
102
|
+
tag = None
|
|
103
|
+
digest = None
|
|
104
|
+
|
|
105
|
+
# Extract digest first (format: name@digest)
|
|
106
|
+
if "@" in original:
|
|
107
|
+
original, digest = original.rsplit("@", 1)
|
|
108
|
+
|
|
109
|
+
# Extract tag (format: name:tag)
|
|
110
|
+
if ":" in original:
|
|
111
|
+
parts = original.split(":")
|
|
112
|
+
if len(parts) >= 2:
|
|
113
|
+
potential_tag = parts[-1]
|
|
114
|
+
# Tag cannot contain '/' - if it does, the colon is part of the registry, separating host and port
|
|
115
|
+
if "/" not in potential_tag:
|
|
116
|
+
original = ":".join(parts[:-1])
|
|
117
|
+
tag = potential_tag
|
|
118
|
+
|
|
119
|
+
# Split by '/' to separate registry/namespace/repository
|
|
120
|
+
parts = original.split("/")
|
|
121
|
+
|
|
122
|
+
if len(parts) == 1:
|
|
123
|
+
# Just repository name (e.g., "nginx")
|
|
124
|
+
repository = parts[0]
|
|
125
|
+
elif len(parts) == 2:
|
|
126
|
+
# Could be namespace/repository or registry/repository
|
|
127
|
+
if "." in parts[0] or ":" in parts[0]:
|
|
128
|
+
# Likely a registry (registry.io:5000/repo or registry.io/repo)
|
|
129
|
+
registry_host, registry_port = parse_registry(parts[0])
|
|
130
|
+
repository = parts[1]
|
|
131
|
+
else:
|
|
132
|
+
# Likely namespace/repository
|
|
133
|
+
namespace = parts[0]
|
|
134
|
+
repository = parts[1]
|
|
135
|
+
elif len(parts) >= 3:
|
|
136
|
+
# registry/namespace/repository or registry/nested/namespace/repository
|
|
137
|
+
registry_host, registry_port = parse_registry(parts[0])
|
|
138
|
+
namespace = "/".join(parts[1:-1])
|
|
139
|
+
repository = parts[-1]
|
|
140
|
+
|
|
141
|
+
# Validate that we found a repository
|
|
142
|
+
if not repository:
|
|
143
|
+
raise ValueError(f"Invalid image reference: no repository found in '{image}'")
|
|
144
|
+
|
|
145
|
+
# Default tag to 'latest' if neither tag nor digest specified. This is Docker's default behavior.
|
|
146
|
+
if tag is None and digest is None:
|
|
147
|
+
tag = "latest"
|
|
148
|
+
|
|
149
|
+
return ImageReference(
|
|
150
|
+
repository=repository,
|
|
151
|
+
namespace=namespace,
|
|
152
|
+
tag=tag,
|
|
153
|
+
digest=digest,
|
|
154
|
+
registry_host=registry_host,
|
|
155
|
+
registry_port=registry_port,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
8
160
|
class ContainerSpec:
|
|
9
161
|
image: str = ""
|
|
10
|
-
ports:
|
|
11
|
-
networks:
|
|
12
|
-
volumes:
|
|
13
|
-
env_vars:
|
|
162
|
+
ports: list[str] = field(default_factory=list)
|
|
163
|
+
networks: list[str] = field(default_factory=list)
|
|
164
|
+
volumes: list[str] = field(default_factory=list)
|
|
165
|
+
env_vars: list[str] = field(default_factory=list)
|
|
166
|
+
labels: list[str] = field(default_factory=list)
|
|
14
167
|
pull_always: bool = False
|
|
15
168
|
|
|
16
169
|
def container_create_args(self):
|
|
@@ -27,6 +180,9 @@ class ContainerSpec:
|
|
|
27
180
|
for env_var in self.env_vars:
|
|
28
181
|
args.append("-e {0}".format(env_var))
|
|
29
182
|
|
|
183
|
+
for label in self.labels:
|
|
184
|
+
args.append("--label {0}".format(label))
|
|
185
|
+
|
|
30
186
|
if self.pull_always:
|
|
31
187
|
args.append("--pull always")
|
|
32
188
|
|
|
@@ -34,7 +190,7 @@ class ContainerSpec:
|
|
|
34
190
|
|
|
35
191
|
return args
|
|
36
192
|
|
|
37
|
-
def diff_from_inspect(self, inspect_dict:
|
|
193
|
+
def diff_from_inspect(self, inspect_dict: dict[str, Any]) -> list[str]:
|
|
38
194
|
# TODO(@minor-fixes): Diff output of "docker inspect" against this spec
|
|
39
195
|
# to determine if the container needs to be recreated. Currently, this
|
|
40
196
|
# function will never recreate when attributes change, which is
|
|
@@ -172,6 +172,8 @@ def ensure_packages(
|
|
|
172
172
|
return
|
|
173
173
|
if isinstance(packages_to_ensure, str):
|
|
174
174
|
packages_to_ensure = [packages_to_ensure]
|
|
175
|
+
if len(packages_to_ensure) == 0:
|
|
176
|
+
return
|
|
175
177
|
|
|
176
178
|
packages: list[PkgInfo] = []
|
|
177
179
|
if isinstance(packages_to_ensure[0], PkgInfo):
|
pyinfra/operations/xbps.py
CHANGED
pyinfra/operations/yum.py
CHANGED
|
@@ -25,6 +25,9 @@ def key(src: str):
|
|
|
25
25
|
|
|
26
26
|
.. code:: python
|
|
27
27
|
|
|
28
|
+
from pyinfra import host
|
|
29
|
+
from pyinfra.operations import dnf
|
|
30
|
+
from pyinfra.facts.server import LinuxDistribution
|
|
28
31
|
linux_id = host.get_fact(LinuxDistribution)["release_meta"].get("ID")
|
|
29
32
|
yum.key(
|
|
30
33
|
name="Add the Docker CentOS gpg key",
|
|
@@ -75,7 +78,7 @@ def repo(
|
|
|
75
78
|
|
|
76
79
|
# Create the repository file from baseurl/etc
|
|
77
80
|
yum.repo(
|
|
78
|
-
name="Add the Docker
|
|
81
|
+
name="Add the Docker repo",
|
|
79
82
|
src="DockerCE",
|
|
80
83
|
baseurl="https://download.docker.com/linux/centos/7/$basearch/stable",
|
|
81
84
|
)
|
pyinfra/operations/zfs.py
CHANGED
pyinfra/operations/zypper.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyinfra
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6
|
|
4
4
|
Summary: pyinfra automates/provisions/manages/deploys infrastructure.
|
|
5
5
|
Project-URL: homepage, https://pyinfra.com
|
|
6
6
|
Project-URL: documentation, https://docs.pyinfra.com
|
|
@@ -29,6 +29,7 @@ Requires-Dist: gevent>=1.5
|
|
|
29
29
|
Requires-Dist: jinja2<4,>3
|
|
30
30
|
Requires-Dist: packaging>=16.1
|
|
31
31
|
Requires-Dist: paramiko<4,>=2.7
|
|
32
|
+
Requires-Dist: pydantic<3,>=2.11
|
|
32
33
|
Requires-Dist: python-dateutil<3,>2
|
|
33
34
|
Requires-Dist: typeguard<5,>=4
|
|
34
35
|
Requires-Dist: typing-extensions; python_version < '3.11'
|
|
@@ -5,32 +5,33 @@ pyinfra/local.py,sha256=wT84xkJc9UBN5isvIVbNpm2fzZaadwE-dkbAwaFQdZk,2808
|
|
|
5
5
|
pyinfra/progress.py,sha256=X3hXZ4Flh_L9FE4ZEWxWoG0R4dA5UPd1FCO-Exd5Xtc,4193
|
|
6
6
|
pyinfra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
pyinfra/version.py,sha256=LZf50PHDzEZv65w0G-iMICoQ9US0U5LWHAOEmNtkF3I,216
|
|
8
|
-
pyinfra/api/__init__.py,sha256=
|
|
9
|
-
pyinfra/api/arguments.py,sha256=
|
|
8
|
+
pyinfra/api/__init__.py,sha256=89brynFpoKWCE513go2pK2wfbGaU1V1gajX3UMm9LVA,964
|
|
9
|
+
pyinfra/api/arguments.py,sha256=mG6A2JgDL6RSFIibjKaocVxbWuFZEtzJ_Is8r6OZ4Mc,12438
|
|
10
10
|
pyinfra/api/arguments_typed.py,sha256=IZuhpmDfW9CP6ASS5Ie-3Wcnxl6bDNR3egU4Mfhbsb4,2303
|
|
11
11
|
pyinfra/api/command.py,sha256=NwF2syxV3zxCbBdHzvJ6ve5G-xwdNTjPHFPwguKVcYs,7741
|
|
12
12
|
pyinfra/api/config.py,sha256=gVDV-aGh6LYOnHtBaivICrd3RBfjFRWy3-K9sG__eP8,9321
|
|
13
13
|
pyinfra/api/connect.py,sha256=jkx07iUL29u9pHHKH4WcNtvxwOA4DIbF7ixguFyuFjo,1984
|
|
14
14
|
pyinfra/api/connectors.py,sha256=nie7JuLxMSC6gqPjmjuCisQ11R-eAQDtMMWF6YbSQ48,659
|
|
15
15
|
pyinfra/api/deploy.py,sha256=Upd92oThQN0zhKbKW8vyPvBuoYiEGStuiEy7kNhZ00Y,3167
|
|
16
|
-
pyinfra/api/exceptions.py,sha256=
|
|
17
|
-
pyinfra/api/facts.py,sha256=
|
|
18
|
-
pyinfra/api/host.py,sha256=
|
|
16
|
+
pyinfra/api/exceptions.py,sha256=dp11JB5OUn48slAldVN8l8m8F8DpUXULIy0-VonzMS0,2004
|
|
17
|
+
pyinfra/api/facts.py,sha256=kT9KPKnDoBnz8Gck21yYDuYXzRzHio-B5ZwSqyj89Iw,9885
|
|
18
|
+
pyinfra/api/host.py,sha256=192rj8fsrHXudfnxzPlYxljXU24pReeWjXtrcCe9Kj4,14214
|
|
19
19
|
pyinfra/api/inventory.py,sha256=i_LBI-Gn5FF-9SVDBH6xefTtvFzjuz12QQiFPGK2TrQ,7864
|
|
20
|
+
pyinfra/api/metadata.py,sha256=73BjwxKKA4mgP7D60K7Z8YIwPC11YN4IXaq26d209BI,1884
|
|
20
21
|
pyinfra/api/operation.py,sha256=WtZyVwPoh9_AytqcCf_W6sMHhWEfSex9RE54aMBHU5M,17053
|
|
21
|
-
pyinfra/api/operations.py,sha256=
|
|
22
|
+
pyinfra/api/operations.py,sha256=JEVLcLeVO81PXd4Vmvn3XuAovZguURoNXBexYQWBnyo,13718
|
|
22
23
|
pyinfra/api/state.py,sha256=cj-JvxOljeDshWvRpq8AMQxdGaUaht8KyuyR3mEsI-Y,12859
|
|
23
|
-
pyinfra/api/util.py,sha256=
|
|
24
|
+
pyinfra/api/util.py,sha256=fwlgiFGFpHPQQ6BVT3SRDDunZBS3fZ7ApTEFuRI6r5M,13276
|
|
24
25
|
pyinfra/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
26
|
pyinfra/connectors/base.py,sha256=0-BKInwTpjbnTakJhMTn_8LUOl81vUmC-q-HzVrwhkw,4703
|
|
26
27
|
pyinfra/connectors/chroot.py,sha256=dBgruen5vS4j-OEFwF6ew-LPBR4kJEIQw_W5nXqlvVg,6064
|
|
27
|
-
pyinfra/connectors/docker.py,sha256=
|
|
28
|
+
pyinfra/connectors/docker.py,sha256=BgSPsiqTY1SxchnSSPsuYNEA8YdWo6KD57h9TIE8YQQ,12679
|
|
28
29
|
pyinfra/connectors/dockerssh.py,sha256=NGG6hSZ3z66RRKt6T0hnG2jiXFLR4P5uudi1COcGnY0,9021
|
|
29
30
|
pyinfra/connectors/local.py,sha256=DJMmZiPgeYvZyW0ANvWjCxF3elmDlmolkY0ktTW3rcg,6990
|
|
30
|
-
pyinfra/connectors/ssh.py,sha256=
|
|
31
|
+
pyinfra/connectors/ssh.py,sha256=zESbhrA8Vp1FuzLdaeu21oHaBwpnYfK4VnbIFLo8oUY,24299
|
|
31
32
|
pyinfra/connectors/ssh_util.py,sha256=CN_5AdTA3RpiWCnXTrRBjez1NsN59hITDzQmXIkZvoE,3683
|
|
32
33
|
pyinfra/connectors/terraform.py,sha256=j-a2yStBLdw1QLZRVnl_9TanDtdyujyCxBO2Oa00rPM,4289
|
|
33
|
-
pyinfra/connectors/util.py,sha256
|
|
34
|
+
pyinfra/connectors/util.py,sha256=XJamDcmPLhTQQIycXUuUovi4herse-ZEI_rJcl-yskE,12029
|
|
34
35
|
pyinfra/connectors/vagrant.py,sha256=0TT73ks64I4Yl-JSZjMBbpWA3VYBkqqLB-fUS8pS8GY,4813
|
|
35
36
|
pyinfra/connectors/scp/__init__.py,sha256=jnO-_8GfkKWhsFcDjAxjOkuUT2RbS22b8P_xPrX889U,44
|
|
36
37
|
pyinfra/connectors/scp/client.py,sha256=l_fPsbgz-7U6Y50ssuKKPFxD_cFoIPtaVXMCYDotbDI,6399
|
|
@@ -44,12 +45,12 @@ pyinfra/facts/brew.py,sha256=nE6YVc2S9zasyJPZmPR5FMeGKPViZYEcpnnBQlDf1EU,2792
|
|
|
44
45
|
pyinfra/facts/bsdinit.py,sha256=SVY4hagjyy1yz8FKWhIbX9fHm5AugvTFl4xQh2FFO74,631
|
|
45
46
|
pyinfra/facts/cargo.py,sha256=qgOClhwZm4COcncDzOZccCzs67nPBi_x6VGiF2UA0sA,687
|
|
46
47
|
pyinfra/facts/choco.py,sha256=mpLleSqNqiaGRgyrhgceno2iPB1_1yjn8UJ90pvOZCs,886
|
|
47
|
-
pyinfra/facts/crontab.py,sha256=
|
|
48
|
+
pyinfra/facts/crontab.py,sha256=mEY7bWvvjir23aUhNwm1mjCmFYHjVsWqrgbAXu1wt3M,5774
|
|
48
49
|
pyinfra/facts/deb.py,sha256=1dR1puwY5wyyhhYYwaEBLjKU9sIyaNBNBlamVZ2KQg0,2074
|
|
49
50
|
pyinfra/facts/dnf.py,sha256=wXatfZWVrrdLY7LM-vHKMg8Md1FiwkqHxmgRYbQqw90,1208
|
|
50
51
|
pyinfra/facts/docker.py,sha256=fqIqMR6HwSYpTUAjhCX8Hk57pcyL6ShIl98H32Ly6HM,3233
|
|
51
52
|
pyinfra/facts/efibootmgr.py,sha256=JPJSokE_RV9JstEPJRECnqSU-B0JCxmrocY8zBOva7M,3555
|
|
52
|
-
pyinfra/facts/files.py,sha256=
|
|
53
|
+
pyinfra/facts/files.py,sha256=xLMXbmYQ8x6Cri44Nh9BOGU0o5OAX39BtXzoOgoZyMM,19462
|
|
53
54
|
pyinfra/facts/flatpak.py,sha256=ovi3duwTqqwvt5GoDRN7R-PpkvR6sQ1SmgEADcSnkUE,1646
|
|
54
55
|
pyinfra/facts/freebsd.py,sha256=za42Di2M2-hcSTPei1YE6BsJxqapm9jysshs9hKJZaY,2161
|
|
55
56
|
pyinfra/facts/gem.py,sha256=aX2-vcEqkxUIP0UJ_SVp9bf4B944oyDjsuujjs5q_9w,654
|
|
@@ -60,7 +61,7 @@ pyinfra/facts/iptables.py,sha256=ORRExNnPR5ysymDbkUjeQWt9mzjSI7su4uQfsu3FlJQ,350
|
|
|
60
61
|
pyinfra/facts/launchd.py,sha256=Nl4EFbGwlXTj8GNWlS9UMZODHr63bve73xmMeqyf2gc,849
|
|
61
62
|
pyinfra/facts/lxd.py,sha256=A2LQN5armY_nI6gV-m1j4l2J2_mMZnvVa1X2RntDnDk,548
|
|
62
63
|
pyinfra/facts/mysql.py,sha256=ZVN6eN0Xetidvq_RAntSCzHgy4jmf8Enrm2mPXxO488,6247
|
|
63
|
-
pyinfra/facts/npm.py,sha256=
|
|
64
|
+
pyinfra/facts/npm.py,sha256=lbiLHoRMZ4POSjK_S5jbqp7ulrDqT-MIUhrI4uYV7BU,857
|
|
64
65
|
pyinfra/facts/openrc.py,sha256=wB4fjzgWCgX6wexBm4jlWv4YH6b4z5_tAqQAO1qO9Kg,1614
|
|
65
66
|
pyinfra/facts/opkg.py,sha256=yTPuzoUyDDn-o7H97lPtyPe-FOkYg5zqkVmfKt9HwY4,7404
|
|
66
67
|
pyinfra/facts/pacman.py,sha256=SPI3jpzZbq_VnJ0z5q7A2Rw___EHVntOz6M19ErGpmQ,1324
|
|
@@ -74,7 +75,7 @@ pyinfra/facts/postgresql.py,sha256=4nusMVvGhtku86KX4O4vjSxh_MamxZy_kmTQvvy0GhE,2
|
|
|
74
75
|
pyinfra/facts/rpm.py,sha256=ikuKYiUmjgvPA84qfE-gbq4Iv4AB5cvor1uKU6uHbXQ,2391
|
|
75
76
|
pyinfra/facts/runit.py,sha256=qok1FTSshiNrN603vjYTKOeM-NIlxwLbwOp-vPbPySo,2131
|
|
76
77
|
pyinfra/facts/selinux.py,sha256=umVGK_6Iuj4Xbw5vhhbpxdUA4Mzg2Fhy7QmaNflNrp8,4650
|
|
77
|
-
pyinfra/facts/server.py,sha256=
|
|
78
|
+
pyinfra/facts/server.py,sha256=mfLHY8R6NxysPr9x_awB1lcxNplgnFFqrYdF30xrgms,23921
|
|
78
79
|
pyinfra/facts/snap.py,sha256=2-c3z1qpOG7prmKJssLpOXmKo_wwdfROryro6gif2vo,2137
|
|
79
80
|
pyinfra/facts/systemd.py,sha256=meHXURtnoxeJbmPzWFTwvhjQBZ2NlQCY8Tj-oHTG_dI,4320
|
|
80
81
|
pyinfra/facts/sysvinit.py,sha256=q1OpHATFJxjLwatcnYRfpTR7_K2c29b4ppmZu-wgC-4,1589
|
|
@@ -90,60 +91,60 @@ pyinfra/facts/util/packaging.py,sha256=Bo7QxYO0Eyj4_i8G27aOWUD_Rfw741RhkEBm3dF5O
|
|
|
90
91
|
pyinfra/facts/util/units.py,sha256=SNHCisxGwZedCOqO9tfOWJpZ5Stc0Wcg9mZcXoKBY0A,714
|
|
91
92
|
pyinfra/facts/util/win_files.py,sha256=S_IQ5kJD6ZgkEcVHajgh7BIMolLV-1q1ghIcwAS-E1Q,2561
|
|
92
93
|
pyinfra/operations/__init__.py,sha256=SOcW337KXIzD_LH-iJJfq14BQcCs5JzwswJ0PIzDgF4,357
|
|
93
|
-
pyinfra/operations/apk.py,sha256=
|
|
94
|
-
pyinfra/operations/apt.py,sha256=
|
|
95
|
-
pyinfra/operations/brew.py,sha256=
|
|
94
|
+
pyinfra/operations/apk.py,sha256=I1tYoPMN3OsIl_TJvmd_G1daqhiynOyK2-O2PxYHlUQ,2169
|
|
95
|
+
pyinfra/operations/apt.py,sha256=BrNbTlw1HRY5ZMOMFF0XCibeC8QsYM6bYlMRPuiUuNo,14767
|
|
96
|
+
pyinfra/operations/brew.py,sha256=o2T3siobQ_1CNDba7OInI2N60ReplRPELxgjEVDcCRg,5199
|
|
96
97
|
pyinfra/operations/bsdinit.py,sha256=okQUQDr2H8Z-cAdfdbPJiuGujsHLuV5gpuMZ1UlICEM,1648
|
|
97
98
|
pyinfra/operations/cargo.py,sha256=mXWd6pb0IR6kzJMmPHwXZN-VJ-B_y8AdOFlrRzDQOZI,1104
|
|
98
99
|
pyinfra/operations/choco.py,sha256=nIj4bWhChOd5DkybpbD-oupaoODgS7lYx6Vrou5ksuc,1547
|
|
99
|
-
pyinfra/operations/crontab.py,sha256=
|
|
100
|
-
pyinfra/operations/dnf.py,sha256=
|
|
101
|
-
pyinfra/operations/docker.py,sha256=
|
|
102
|
-
pyinfra/operations/files.py,sha256=
|
|
103
|
-
pyinfra/operations/flatpak.py,sha256=
|
|
104
|
-
pyinfra/operations/gem.py,sha256=
|
|
105
|
-
pyinfra/operations/git.py,sha256=
|
|
106
|
-
pyinfra/operations/iptables.py,sha256=
|
|
100
|
+
pyinfra/operations/crontab.py,sha256=L1U_fBvgXkbfbpzb6OzUBrrY-RuvvPlbW5FqDmAT8rI,6644
|
|
101
|
+
pyinfra/operations/dnf.py,sha256=wMFUoUB679bVydt01N7Sd7Cs16RhAaLca-zsmQU86rk,5727
|
|
102
|
+
pyinfra/operations/docker.py,sha256=J_vQwQmCZEuNASFrRjeudrr_ZrpbStdXybGGej4VMxc,14161
|
|
103
|
+
pyinfra/operations/files.py,sha256=jqkYIPn94z4MRqH1eU-ooOJzuQyle8wYiyDvFfXDMPI,68492
|
|
104
|
+
pyinfra/operations/flatpak.py,sha256=Eif5KZkWOVElKF4hL5xOyk_oZEOziHqyyDxGHZ1KPYk,2366
|
|
105
|
+
pyinfra/operations/gem.py,sha256=YtVUKVp1zYPAxy2t1ryw-vgucBVYJASOxhauLOvRj6U,1175
|
|
106
|
+
pyinfra/operations/git.py,sha256=IE41_MGOZ3nc7gtIzVssQDgi1eSoCbK07jm9EniFt54,13287
|
|
107
|
+
pyinfra/operations/iptables.py,sha256=ETdNPFkc5DyydBr7IncxYdR7DBAFQzE4X85AoGZGBZI,9386
|
|
107
108
|
pyinfra/operations/launchd.py,sha256=6HWvqoQ74idV_NStOEmFXwu0dmTv7YDvFtsK8An2Lu4,1177
|
|
108
|
-
pyinfra/operations/lxd.py,sha256=
|
|
109
|
-
pyinfra/operations/mysql.py,sha256=
|
|
109
|
+
pyinfra/operations/lxd.py,sha256=eTsLOni3LAlq-f4dj4OJiHkLlhhMI7fW1N0M_7ekon4,1785
|
|
110
|
+
pyinfra/operations/mysql.py,sha256=kQmshmia7rNh9pZI3iGk95PG4T0TadChCiDYGy8jbuw,19896
|
|
110
111
|
pyinfra/operations/npm.py,sha256=bUmfQsClZ2YcHiihiC7k5widIXIi6lbfx_32iyaAKfo,1499
|
|
111
112
|
pyinfra/operations/openrc.py,sha256=AThQQO7u_pO0M-rQbxkX7EWDuR569smkoPVaQoRoFeE,1834
|
|
112
|
-
pyinfra/operations/opkg.py,sha256=
|
|
113
|
-
pyinfra/operations/pacman.py,sha256=
|
|
114
|
-
pyinfra/operations/pip.py,sha256=
|
|
115
|
-
pyinfra/operations/pipx.py,sha256=
|
|
116
|
-
pyinfra/operations/pkg.py,sha256=
|
|
117
|
-
pyinfra/operations/pkgin.py,sha256=
|
|
118
|
-
pyinfra/operations/postgres.py,sha256=
|
|
113
|
+
pyinfra/operations/opkg.py,sha256=ebv-SS0WaHp0dxKF2HnSY6m__vhQYNlh5zzbjgEzK9Q,2648
|
|
114
|
+
pyinfra/operations/pacman.py,sha256=e10D4XUwT0VTtZzBeB1tRomr9pEfun1VvNH1ia5eBhI,1748
|
|
115
|
+
pyinfra/operations/pip.py,sha256=uTfK36_vBNqCXsWMU4iypOLhnhKduJK6f0b9srlMEqg,6038
|
|
116
|
+
pyinfra/operations/pipx.py,sha256=oWcJXKogC43cKNsf625FU4ClIAV6KZA26o2cRoa3avQ,2844
|
|
117
|
+
pyinfra/operations/pkg.py,sha256=m5okKIXU1xIIcNQXQnFKXbL97ZcokmGn-hnruokE7is,2341
|
|
118
|
+
pyinfra/operations/pkgin.py,sha256=6bZyvdjYDqn-0a-r23O_122r1QSjHP8SkJiWZ_k231A,2037
|
|
119
|
+
pyinfra/operations/postgres.py,sha256=GlIn5aAVNOjs7cSyF3CFY6LO3dC0ZQQ0wAs_y0JJHis,13417
|
|
119
120
|
pyinfra/operations/postgresql.py,sha256=agZjL2W4yxigk9ThIC0V_3wvmcWVdX308aJO24WkN6g,833
|
|
120
|
-
pyinfra/operations/puppet.py,sha256=
|
|
121
|
-
pyinfra/operations/python.py,sha256=
|
|
121
|
+
pyinfra/operations/puppet.py,sha256=e9vO6SQnkMoyVWjy3oP08GaXgyIPajoA2QJ4g4ib4-M,907
|
|
122
|
+
pyinfra/operations/python.py,sha256=5IXcywwhwITPRJAs8BEL5H5vSPvk_QFMbhF8Iuexp_s,2067
|
|
122
123
|
pyinfra/operations/runit.py,sha256=-K0GhORE56J4Gjh7PCriSx9zZI7XJV-cIb-LnnSuKdY,5162
|
|
123
|
-
pyinfra/operations/selinux.py,sha256=
|
|
124
|
-
pyinfra/operations/server.py,sha256=
|
|
125
|
-
pyinfra/operations/snap.py,sha256=
|
|
126
|
-
pyinfra/operations/ssh.py,sha256=
|
|
127
|
-
pyinfra/operations/systemd.py,sha256=
|
|
128
|
-
pyinfra/operations/sysvinit.py,sha256=
|
|
124
|
+
pyinfra/operations/selinux.py,sha256=AZLLpYHBZbpLftUbigM7vjkjEajOQEQsLKc5y9OIpSQ,5995
|
|
125
|
+
pyinfra/operations/server.py,sha256=7CrmzWqTjQkync0y_Wdqt82VlmNn293XmoN720MSUWo,31291
|
|
126
|
+
pyinfra/operations/snap.py,sha256=vMCdH274ToI1Pi3un3qihZMS9UW9fXQD5PzLd7lT49E,3097
|
|
127
|
+
pyinfra/operations/ssh.py,sha256=8KdkzxevejX-PfQ6Lgt5c_sk8TutCxUOl9AbvwKUrlE,5677
|
|
128
|
+
pyinfra/operations/systemd.py,sha256=4geQSsuNNBC4F5S_gZBXLfH2UI0JgZZckQfNFJD2gDY,4031
|
|
129
|
+
pyinfra/operations/sysvinit.py,sha256=FMkjQ_jWxs9UR_QSRrogYMHT7lS4cmkDco-rU3waOWE,4119
|
|
129
130
|
pyinfra/operations/upstart.py,sha256=pHb9RGnVhT14A_y6OezfOH-lmniKpiyJqpeoOJl0beE,1978
|
|
130
131
|
pyinfra/operations/vzctl.py,sha256=2u2CDkuDjzHBRQ54HfyfLpLrsbT8U7_05EEjbbhKUiU,3110
|
|
131
|
-
pyinfra/operations/xbps.py,sha256=
|
|
132
|
-
pyinfra/operations/yum.py,sha256=
|
|
133
|
-
pyinfra/operations/zfs.py,sha256=
|
|
134
|
-
pyinfra/operations/zypper.py,sha256=
|
|
132
|
+
pyinfra/operations/xbps.py,sha256=46t05vAdXj9r_VElMT0mxKTtIgeDKVK54wRB_2bSGCI,1552
|
|
133
|
+
pyinfra/operations/yum.py,sha256=Rls0ypn5_OaSGkpBHy---TLOw0fmvrecTQ8CuDR0VJE,5728
|
|
134
|
+
pyinfra/operations/zfs.py,sha256=1V-T04RN7Goxqj-wQzsqeXfCV5H1hEfys3l362lcRek,5326
|
|
135
|
+
pyinfra/operations/zypper.py,sha256=WEUmuRux7_TOdzeTZA_3I5qtqYPpr0N175qIKbYtI5M,5601
|
|
135
136
|
pyinfra/operations/freebsd/__init__.py,sha256=PXsCLQG29VhimYw4uwwB2FcDt6CrofOtD3LTHC-ik-8,362
|
|
136
137
|
pyinfra/operations/freebsd/freebsd_update.py,sha256=lH0wB_i6DkaXQnDPjsDq8ocO1hYHL0v_a1go4exYcR8,1864
|
|
137
138
|
pyinfra/operations/freebsd/pkg.py,sha256=3AyfI0-_9F4ho47KqZsOMQocwNtTF2q9g0i6TffJVak,4413
|
|
138
139
|
pyinfra/operations/freebsd/service.py,sha256=1f7nTHELnhs3HBSrMFsmopVgYFMIwB8Se88yneRQ8Rw,3198
|
|
139
140
|
pyinfra/operations/freebsd/sysrc.py,sha256=eg7u_JsCge_uKq3Ysc_mohUc6qgJrOZStp_B_l2Hav4,2330
|
|
140
141
|
pyinfra/operations/util/__init__.py,sha256=ZAHjeCXtLo0TIOSfZ9h0Sh5IXXRCspfHs3RR1l8tQCE,366
|
|
141
|
-
pyinfra/operations/util/docker.py,sha256=
|
|
142
|
+
pyinfra/operations/util/docker.py,sha256=OCjlyxjuNP6Ki8zU6-cQkhgM-FgKsylD-dEhR7JNc8Y,11920
|
|
142
143
|
pyinfra/operations/util/files.py,sha256=PFJDccNTwXK4tIoFB8ycRj7yD1x7LpSflBy7mPQtJCg,7148
|
|
143
|
-
pyinfra/operations/util/packaging.py,sha256=
|
|
144
|
+
pyinfra/operations/util/packaging.py,sha256=RXZgUlWqEBtArK7wJfXE2Ndvl_aP0YjjksxxCnPpexk,12086
|
|
144
145
|
pyinfra/operations/util/service.py,sha256=kJd1zj4-sAaGIp5Ts7yAJznogWaGr8oQTztwenLAr7Y,1309
|
|
145
146
|
pyinfra_cli/__init__.py,sha256=G0X7tNdqT45uWuK3aHIKxMdDeCgJ7zHo6vbxoG6zy_8,284
|
|
146
|
-
pyinfra_cli/cli.py,sha256=
|
|
147
|
+
pyinfra_cli/cli.py,sha256=vlD9YyJaSy0mZu2J6pvDvBxka6cu6pRCvDj_ZZUDqXY,21285
|
|
147
148
|
pyinfra_cli/commands.py,sha256=J-mCJYvDebJ8M7o3HreB2zToa871-xO6_KjVhPLeHho,1832
|
|
148
149
|
pyinfra_cli/exceptions.py,sha256=RRaOprL7SmVv--FLy4x7fxeTitx9wYI0Y3_h01LfhJA,4901
|
|
149
150
|
pyinfra_cli/inventory.py,sha256=JYSixJZKY8GNWlOxh-nGDsAknCdaAktlWAmdg13kvNk,11771
|
|
@@ -152,8 +153,8 @@ pyinfra_cli/main.py,sha256=1CR3IS-O6BkAzkn7UW6pdKktTmN4Qnt0_jPdkhueRM8,936
|
|
|
152
153
|
pyinfra_cli/prints.py,sha256=1h6vgKVRKUxcGz_HdyEEDUvkp-lgiiVGwx3hc9rw24A,10434
|
|
153
154
|
pyinfra_cli/util.py,sha256=8KKW5LTHX4ebbwbHqMvLqwjZ11mOHI-xIYn-cZCWltg,6722
|
|
154
155
|
pyinfra_cli/virtualenv.py,sha256=wRNxOPcUkbD_Pzuj-Lnrz1KxGmsLlb2ObmCTFrdD-S8,2474
|
|
155
|
-
pyinfra-3.
|
|
156
|
-
pyinfra-3.
|
|
157
|
-
pyinfra-3.
|
|
158
|
-
pyinfra-3.
|
|
159
|
-
pyinfra-3.
|
|
156
|
+
pyinfra-3.6.dist-info/METADATA,sha256=8nSBGBw02ni-nBp6iJsQ6hzoHPoytQcD8jKptRxm4Jg,5771
|
|
157
|
+
pyinfra-3.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
158
|
+
pyinfra-3.6.dist-info/entry_points.txt,sha256=b1nLI6oVRvkeQDS00xcYGdGl4XVR_3tMbKs6T58-NW4,507
|
|
159
|
+
pyinfra-3.6.dist-info/licenses/LICENSE.md,sha256=BzCnRYLJv0yb-FJuEd_XOrrQSOEQKzIVo0yHT8taNnM,1076
|
|
160
|
+
pyinfra-3.6.dist-info/RECORD,,
|
pyinfra_cli/cli.py
CHANGED
|
@@ -2,6 +2,7 @@ import logging
|
|
|
2
2
|
import sys
|
|
3
3
|
import warnings
|
|
4
4
|
from fnmatch import fnmatch
|
|
5
|
+
from getpass import getpass
|
|
5
6
|
from os import chdir as os_chdir, getcwd, path
|
|
6
7
|
from typing import Iterable, List, Tuple, Union
|
|
7
8
|
|
|
@@ -116,6 +117,12 @@ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
|
|
116
117
|
help="Whether to execute operations with sudo.",
|
|
117
118
|
)
|
|
118
119
|
@click.option("--sudo-user", help="Which user to sudo when sudoing.")
|
|
120
|
+
@click.option(
|
|
121
|
+
"--same-sudo-password",
|
|
122
|
+
is_flag=True,
|
|
123
|
+
default=False,
|
|
124
|
+
help="All hosts have the same sudo password, so ask only once.",
|
|
125
|
+
)
|
|
119
126
|
@click.option(
|
|
120
127
|
"--use-sudo-password",
|
|
121
128
|
is_flag=True,
|
|
@@ -274,6 +281,7 @@ def _main(
|
|
|
274
281
|
ssh_key,
|
|
275
282
|
ssh_key_password: str,
|
|
276
283
|
ssh_password: str,
|
|
284
|
+
same_sudo_password: bool,
|
|
277
285
|
shell_executable,
|
|
278
286
|
sudo: bool,
|
|
279
287
|
sudo_user: str,
|
|
@@ -326,6 +334,7 @@ def _main(
|
|
|
326
334
|
sudo,
|
|
327
335
|
sudo_user,
|
|
328
336
|
use_sudo_password,
|
|
337
|
+
same_sudo_password,
|
|
329
338
|
su_user,
|
|
330
339
|
parallel,
|
|
331
340
|
shell_executable,
|
|
@@ -568,6 +577,7 @@ def _set_config(
|
|
|
568
577
|
sudo,
|
|
569
578
|
sudo_user,
|
|
570
579
|
use_sudo_password,
|
|
580
|
+
same_sudo_password,
|
|
571
581
|
su_user,
|
|
572
582
|
parallel,
|
|
573
583
|
shell_executable,
|
|
@@ -598,6 +608,9 @@ def _set_config(
|
|
|
598
608
|
if use_sudo_password:
|
|
599
609
|
config.USE_SUDO_PASSWORD = use_sudo_password
|
|
600
610
|
|
|
611
|
+
if same_sudo_password:
|
|
612
|
+
config.SUDO_PASSWORD = getpass("sudo password: ")
|
|
613
|
+
|
|
601
614
|
if su_user:
|
|
602
615
|
config.SU_USER = su_user
|
|
603
616
|
|
|
File without changes
|
|
File without changes
|