pyinfra 2.9.2__py2.py3-none-any.whl → 3.0b1__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.
- pyinfra/api/__init__.py +3 -0
- pyinfra/api/arguments.py +261 -255
- pyinfra/api/arguments_typed.py +77 -0
- pyinfra/api/command.py +66 -53
- pyinfra/api/config.py +27 -22
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +2 -24
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +77 -113
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +17 -25
- pyinfra/api/operation.py +232 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +55 -70
- pyinfra/connectors/base.py +150 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +227 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +195 -207
- pyinfra/connectors/ssh.py +528 -615
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +212 -137
- pyinfra/connectors/vagrant.py +55 -48
- pyinfra/context.py +3 -2
- pyinfra/facts/docker.py +1 -0
- pyinfra/facts/files.py +45 -32
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +1 -1
- pyinfra/facts/hardware.py +4 -2
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/mysql.py +1 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +5 -161
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +77 -30
- pyinfra/facts/systemd.py +29 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/util/packaging.py +4 -2
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +3 -3
- pyinfra/operations/apt.py +25 -47
- pyinfra/operations/brew.py +7 -14
- pyinfra/operations/bsdinit.py +4 -4
- pyinfra/operations/cargo.py +1 -1
- pyinfra/operations/choco.py +1 -1
- pyinfra/operations/dnf.py +4 -4
- pyinfra/operations/files.py +108 -321
- pyinfra/operations/gem.py +1 -1
- pyinfra/operations/git.py +6 -37
- pyinfra/operations/iptables.py +2 -10
- pyinfra/operations/launchd.py +1 -1
- pyinfra/operations/lxd.py +1 -9
- pyinfra/operations/mysql.py +5 -28
- pyinfra/operations/npm.py +1 -1
- pyinfra/operations/openrc.py +1 -1
- pyinfra/operations/pacman.py +3 -3
- pyinfra/operations/pip.py +14 -15
- pyinfra/operations/pkg.py +1 -1
- pyinfra/operations/pkgin.py +3 -3
- pyinfra/operations/postgres.py +347 -0
- pyinfra/operations/postgresql.py +17 -380
- pyinfra/operations/python.py +2 -17
- pyinfra/operations/selinux.py +5 -28
- pyinfra/operations/server.py +59 -84
- pyinfra/operations/snap.py +1 -3
- pyinfra/operations/ssh.py +8 -23
- pyinfra/operations/systemd.py +7 -7
- pyinfra/operations/sysvinit.py +3 -12
- pyinfra/operations/upstart.py +4 -4
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/files.py +2 -2
- pyinfra/operations/util/packaging.py +6 -24
- pyinfra/operations/util/service.py +18 -37
- pyinfra/operations/vzctl.py +2 -2
- pyinfra/operations/xbps.py +3 -3
- pyinfra/operations/yum.py +4 -4
- pyinfra/operations/zypper.py +4 -4
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/METADATA +19 -22
- pyinfra-3.0b1.dist-info/RECORD +163 -0
- pyinfra-3.0b1.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +2 -0
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +83 -42
- pyinfra_cli/inventory.py +19 -4
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +93 -129
- pyinfra_cli/util.py +60 -29
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +13 -13
- tests/test_api/test_api_deploys.py +28 -29
- tests/test_api/test_api_facts.py +60 -98
- tests/test_api/test_api_operations.py +100 -200
- tests/test_cli/test_cli.py +18 -49
- tests/test_cli/test_cli_deploy.py +11 -37
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_chroot.py +6 -6
- tests/test_connectors/test_docker.py +4 -4
- tests/test_connectors/test_dockerssh.py +38 -50
- tests/test_connectors/test_local.py +11 -12
- tests/test_connectors/test_ssh.py +66 -107
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +4 -4
- pyinfra/api/operation.pyi +0 -117
- pyinfra/connectors/ansible.py +0 -171
- pyinfra/connectors/mech.py +0 -186
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -320
- pyinfra/facts/windows.py +0 -366
- pyinfra/facts/windows_files.py +0 -90
- pyinfra/operations/windows.py +0 -59
- pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.2.dist-info/RECORD +0 -170
- pyinfra-2.9.2.dist-info/entry_points.txt +0 -14
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- tests/test_connectors/test_winrm.py +0 -76
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/WHEEL +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/top_level.txt +0 -0
|
@@ -45,18 +45,17 @@ class TestLocalConnector(TestCase):
|
|
|
45
45
|
command = "echo Šablony"
|
|
46
46
|
self.fake_popen_mock().returncode = 0
|
|
47
47
|
|
|
48
|
-
out = host.run_shell_command(command,
|
|
49
|
-
assert len(out) ==
|
|
48
|
+
out = host.run_shell_command(command, _stdin="hello", print_output=True)
|
|
49
|
+
assert len(out) == 2
|
|
50
50
|
|
|
51
|
-
status,
|
|
51
|
+
status, output = out
|
|
52
52
|
assert status is True
|
|
53
53
|
self.fake_popen_mock().stdin.write.assert_called_with(b"hello\n")
|
|
54
54
|
|
|
55
55
|
combined_out = host.run_shell_command(
|
|
56
56
|
command,
|
|
57
|
-
|
|
57
|
+
_stdin="hello",
|
|
58
58
|
print_output=True,
|
|
59
|
-
return_combined_output=True,
|
|
60
59
|
)
|
|
61
60
|
assert len(combined_out) == 2
|
|
62
61
|
|
|
@@ -79,9 +78,9 @@ class TestLocalConnector(TestCase):
|
|
|
79
78
|
self.fake_popen_mock().returncode = 0
|
|
80
79
|
|
|
81
80
|
out = host.run_shell_command(command, print_output=True, print_input=True)
|
|
82
|
-
assert len(out) ==
|
|
81
|
+
assert len(out) == 2
|
|
83
82
|
|
|
84
|
-
status,
|
|
83
|
+
status, output = out
|
|
85
84
|
assert status is True
|
|
86
85
|
|
|
87
86
|
self.fake_popen_mock.assert_called_with(
|
|
@@ -105,8 +104,8 @@ class TestLocalConnector(TestCase):
|
|
|
105
104
|
command = "echo hi"
|
|
106
105
|
self.fake_popen_mock().returncode = 1
|
|
107
106
|
|
|
108
|
-
out = host.run_shell_command(command,
|
|
109
|
-
assert len(out) ==
|
|
107
|
+
out = host.run_shell_command(command, _success_exit_codes=[1])
|
|
108
|
+
assert len(out) == 2
|
|
110
109
|
assert out[0] is True
|
|
111
110
|
|
|
112
111
|
def test_run_shell_command_error(self):
|
|
@@ -118,7 +117,7 @@ class TestLocalConnector(TestCase):
|
|
|
118
117
|
self.fake_popen_mock().returncode = 1
|
|
119
118
|
|
|
120
119
|
out = host.run_shell_command(command)
|
|
121
|
-
assert len(out) ==
|
|
120
|
+
assert len(out) == 2
|
|
122
121
|
assert out[0] is False
|
|
123
122
|
|
|
124
123
|
def test_put_file(self):
|
|
@@ -210,7 +209,7 @@ class TestLocalConnector(TestCase):
|
|
|
210
209
|
command = "echo Šablony"
|
|
211
210
|
self.fake_popen_mock().returncode = 0
|
|
212
211
|
|
|
213
|
-
host.run_shell_command(command,
|
|
212
|
+
host.run_shell_command(command, _stdin=["hello", "abc"], print_output=True)
|
|
214
213
|
self.fake_popen_mock().stdin.write.assert_has_calls(
|
|
215
214
|
[
|
|
216
215
|
call(b"hello\n"),
|
|
@@ -226,7 +225,7 @@ class TestLocalConnector(TestCase):
|
|
|
226
225
|
command = "echo Šablony"
|
|
227
226
|
self.fake_popen_mock().returncode = 0
|
|
228
227
|
|
|
229
|
-
host.run_shell_command(command,
|
|
228
|
+
host.run_shell_command(command, _stdin=StringIO("hello\nabc"), print_output=True)
|
|
230
229
|
self.fake_popen_mock().stdin.write.assert_has_calls(
|
|
231
230
|
[
|
|
232
231
|
call(b"hello\n"),
|
|
@@ -10,7 +10,6 @@ import pyinfra
|
|
|
10
10
|
from pyinfra.api import Config, MaskString, State, StringCommand
|
|
11
11
|
from pyinfra.api.connect import connect_all
|
|
12
12
|
from pyinfra.api.exceptions import ConnectError, PyinfraError
|
|
13
|
-
from pyinfra.connectors.ssh import _get_sftp_connection
|
|
14
13
|
|
|
15
14
|
from ..util import make_inventory
|
|
16
15
|
|
|
@@ -28,7 +27,6 @@ class TestSSHConnector(TestCase):
|
|
|
28
27
|
def setUp(self):
|
|
29
28
|
self.fake_connect_patch = patch("pyinfra.connectors.ssh.SSHClient.connect")
|
|
30
29
|
self.fake_connect_mock = self.fake_connect_patch.start()
|
|
31
|
-
_get_sftp_connection.cache = {}
|
|
32
30
|
|
|
33
31
|
def tearDown(self):
|
|
34
32
|
self.fake_connect_patch.stop()
|
|
@@ -58,8 +56,8 @@ class TestSSHConnector(TestCase):
|
|
|
58
56
|
|
|
59
57
|
assert len(state.active_hosts) == 2
|
|
60
58
|
|
|
61
|
-
@patch("pyinfra.connectors.
|
|
62
|
-
@patch("pyinfra.connectors.
|
|
59
|
+
@patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True)
|
|
60
|
+
@patch("pyinfra.connectors.ssh_util.RSAKey.from_private_key_file")
|
|
63
61
|
def test_connect_exceptions(self, fake_key_open):
|
|
64
62
|
for exception_class in (
|
|
65
63
|
AuthenticationException,
|
|
@@ -83,8 +81,8 @@ class TestSSHConnector(TestCase):
|
|
|
83
81
|
def test_connect_with_rsa_ssh_key(self):
|
|
84
82
|
state = State(make_inventory(hosts=(("somehost", {"ssh_key": "testkey"}),)), Config())
|
|
85
83
|
|
|
86
|
-
with patch("pyinfra.connectors.
|
|
87
|
-
"pyinfra.connectors.
|
|
84
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
85
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
88
86
|
) as fake_key_open:
|
|
89
87
|
fake_key = MagicMock()
|
|
90
88
|
fake_key_open.return_value = fake_key
|
|
@@ -104,10 +102,10 @@ class TestSSHConnector(TestCase):
|
|
|
104
102
|
pkey=fake_key,
|
|
105
103
|
timeout=10,
|
|
106
104
|
username="vagrant",
|
|
107
|
-
_pyinfra_ssh_forward_agent=
|
|
105
|
+
_pyinfra_ssh_forward_agent=False,
|
|
108
106
|
_pyinfra_ssh_config_file=None,
|
|
109
107
|
_pyinfra_ssh_known_hosts_file=None,
|
|
110
|
-
_pyinfra_ssh_strict_host_key_checking=
|
|
108
|
+
_pyinfra_ssh_strict_host_key_checking="accept-new",
|
|
111
109
|
_pyinfra_ssh_paramiko_connect_kwargs=None,
|
|
112
110
|
)
|
|
113
111
|
|
|
@@ -128,8 +126,8 @@ class TestSSHConnector(TestCase):
|
|
|
128
126
|
Config(),
|
|
129
127
|
)
|
|
130
128
|
|
|
131
|
-
with patch("pyinfra.connectors.
|
|
132
|
-
"pyinfra.connectors.
|
|
129
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
130
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
133
131
|
) as fake_key_open:
|
|
134
132
|
fake_key = MagicMock()
|
|
135
133
|
|
|
@@ -150,11 +148,11 @@ class TestSSHConnector(TestCase):
|
|
|
150
148
|
def test_connect_with_rsa_ssh_key_password_from_prompt(self):
|
|
151
149
|
state = State(make_inventory(hosts=(("somehost", {"ssh_key": "testkey"}),)), Config())
|
|
152
150
|
|
|
153
|
-
with patch("pyinfra.connectors.
|
|
154
|
-
"pyinfra.connectors.
|
|
151
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
152
|
+
"pyinfra.connectors.ssh_util.getpass",
|
|
155
153
|
lambda *args, **kwargs: "testpass",
|
|
156
154
|
), patch(
|
|
157
|
-
"pyinfra.connectors.
|
|
155
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
158
156
|
) as fake_key_open:
|
|
159
157
|
fake_key = MagicMock()
|
|
160
158
|
|
|
@@ -177,8 +175,8 @@ class TestSSHConnector(TestCase):
|
|
|
177
175
|
def test_connect_with_rsa_ssh_key_missing_password(self):
|
|
178
176
|
state = State(make_inventory(hosts=(("somehost", {"ssh_key": "testkey"}),)), Config())
|
|
179
177
|
|
|
180
|
-
with patch("pyinfra.connectors.
|
|
181
|
-
"pyinfra.connectors.
|
|
178
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
179
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
182
180
|
) as fake_key_open:
|
|
183
181
|
fake_key_open.side_effect = make_raise_exception_function(PasswordRequiredException)
|
|
184
182
|
|
|
@@ -203,17 +201,17 @@ class TestSSHConnector(TestCase):
|
|
|
203
201
|
fake_fail_from_private_key_file = MagicMock()
|
|
204
202
|
fake_fail_from_private_key_file.side_effect = make_raise_exception_function(SSHException)
|
|
205
203
|
|
|
206
|
-
with patch("pyinfra.connectors.
|
|
207
|
-
"pyinfra.connectors.
|
|
204
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
205
|
+
"pyinfra.connectors.ssh_util.DSSKey.from_private_key_file",
|
|
208
206
|
fake_fail_from_private_key_file,
|
|
209
207
|
), patch(
|
|
210
|
-
"pyinfra.connectors.
|
|
208
|
+
"pyinfra.connectors.ssh_util.ECDSAKey.from_private_key_file",
|
|
211
209
|
fake_fail_from_private_key_file,
|
|
212
210
|
), patch(
|
|
213
|
-
"pyinfra.connectors.
|
|
211
|
+
"pyinfra.connectors.ssh_util.Ed25519Key.from_private_key_file",
|
|
214
212
|
fake_fail_from_private_key_file,
|
|
215
213
|
), patch(
|
|
216
|
-
"pyinfra.connectors.
|
|
214
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
217
215
|
) as fake_key_open:
|
|
218
216
|
|
|
219
217
|
def fake_key_open_fail(*args, **kwargs):
|
|
@@ -236,10 +234,10 @@ class TestSSHConnector(TestCase):
|
|
|
236
234
|
def test_connect_with_dss_ssh_key(self):
|
|
237
235
|
state = State(make_inventory(hosts=(("somehost", {"ssh_key": "testkey"}),)), Config())
|
|
238
236
|
|
|
239
|
-
with patch("pyinfra.connectors.
|
|
240
|
-
"pyinfra.connectors.
|
|
237
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
238
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
241
239
|
) as fake_rsa_key_open, patch(
|
|
242
|
-
"pyinfra.connectors.
|
|
240
|
+
"pyinfra.connectors.ssh_util.DSSKey.from_private_key_file",
|
|
243
241
|
) as fake_key_open: # noqa
|
|
244
242
|
fake_rsa_key_open.side_effect = make_raise_exception_function(SSHException)
|
|
245
243
|
|
|
@@ -259,10 +257,10 @@ class TestSSHConnector(TestCase):
|
|
|
259
257
|
pkey=fake_key,
|
|
260
258
|
timeout=10,
|
|
261
259
|
username="vagrant",
|
|
262
|
-
_pyinfra_ssh_forward_agent=
|
|
260
|
+
_pyinfra_ssh_forward_agent=False,
|
|
263
261
|
_pyinfra_ssh_config_file=None,
|
|
264
262
|
_pyinfra_ssh_known_hosts_file=None,
|
|
265
|
-
_pyinfra_ssh_strict_host_key_checking=
|
|
263
|
+
_pyinfra_ssh_strict_host_key_checking="accept-new",
|
|
266
264
|
_pyinfra_ssh_paramiko_connect_kwargs=None,
|
|
267
265
|
)
|
|
268
266
|
|
|
@@ -283,10 +281,10 @@ class TestSSHConnector(TestCase):
|
|
|
283
281
|
Config(),
|
|
284
282
|
)
|
|
285
283
|
|
|
286
|
-
with patch("pyinfra.connectors.
|
|
287
|
-
"pyinfra.connectors.
|
|
284
|
+
with patch("pyinfra.connectors.ssh_util.path.isfile", lambda *args, **kwargs: True), patch(
|
|
285
|
+
"pyinfra.connectors.ssh_util.RSAKey.from_private_key_file",
|
|
288
286
|
) as fake_rsa_key_open, patch(
|
|
289
|
-
"pyinfra.connectors.
|
|
287
|
+
"pyinfra.connectors.ssh_util.DSSKey.from_private_key_file",
|
|
290
288
|
) as fake_dss_key_open: # noqa
|
|
291
289
|
|
|
292
290
|
def fake_rsa_key_open_fail(*args, **kwargs):
|
|
@@ -318,10 +316,10 @@ class TestSSHConnector(TestCase):
|
|
|
318
316
|
pkey=fake_dss_key,
|
|
319
317
|
timeout=10,
|
|
320
318
|
username="vagrant",
|
|
321
|
-
_pyinfra_ssh_forward_agent=
|
|
319
|
+
_pyinfra_ssh_forward_agent=False,
|
|
322
320
|
_pyinfra_ssh_config_file=None,
|
|
323
321
|
_pyinfra_ssh_known_hosts_file=None,
|
|
324
|
-
_pyinfra_ssh_strict_host_key_checking=
|
|
322
|
+
_pyinfra_ssh_strict_host_key_checking="accept-new",
|
|
325
323
|
_pyinfra_ssh_paramiko_connect_kwargs=None,
|
|
326
324
|
)
|
|
327
325
|
|
|
@@ -362,18 +360,17 @@ class TestSSHConnector(TestCase):
|
|
|
362
360
|
command = "echo Šablony"
|
|
363
361
|
fake_stdout.channel.recv_exit_status.return_value = 0
|
|
364
362
|
|
|
365
|
-
out = host.run_shell_command(command,
|
|
366
|
-
assert len(out) ==
|
|
363
|
+
out = host.run_shell_command(command, _stdin="hello", print_output=True)
|
|
364
|
+
assert len(out) == 2
|
|
367
365
|
|
|
368
|
-
status,
|
|
366
|
+
status, output = out
|
|
369
367
|
assert status is True
|
|
370
368
|
fake_stdin.write.assert_called_with(b"hello\n")
|
|
371
369
|
|
|
372
370
|
combined_out = host.run_shell_command(
|
|
373
371
|
command,
|
|
374
|
-
|
|
372
|
+
_stdin="hello",
|
|
375
373
|
print_output=True,
|
|
376
|
-
return_combined_output=True,
|
|
377
374
|
)
|
|
378
375
|
assert len(combined_out) == 2
|
|
379
376
|
|
|
@@ -397,9 +394,9 @@ class TestSSHConnector(TestCase):
|
|
|
397
394
|
fake_stdout.channel.recv_exit_status.return_value = 0
|
|
398
395
|
|
|
399
396
|
out = host.run_shell_command(command, print_output=True, print_input=True)
|
|
400
|
-
assert len(out) ==
|
|
397
|
+
assert len(out) == 2
|
|
401
398
|
|
|
402
|
-
status,
|
|
399
|
+
status, output = out
|
|
403
400
|
assert status is True
|
|
404
401
|
|
|
405
402
|
fake_ssh.exec_command.assert_called_with(
|
|
@@ -428,8 +425,8 @@ class TestSSHConnector(TestCase):
|
|
|
428
425
|
command = "echo hi"
|
|
429
426
|
fake_stdout.channel.recv_exit_status.return_value = 1
|
|
430
427
|
|
|
431
|
-
out = host.run_shell_command(command,
|
|
432
|
-
assert len(out) ==
|
|
428
|
+
out = host.run_shell_command(command, _success_exit_codes=[1])
|
|
429
|
+
assert len(out) == 2
|
|
433
430
|
assert out[0] is True
|
|
434
431
|
|
|
435
432
|
@patch("pyinfra.connectors.ssh.SSHClient")
|
|
@@ -449,47 +446,9 @@ class TestSSHConnector(TestCase):
|
|
|
449
446
|
fake_stdout.channel.recv_exit_status.return_value = 1
|
|
450
447
|
|
|
451
448
|
out = host.run_shell_command(command)
|
|
452
|
-
assert len(out) ==
|
|
449
|
+
assert len(out) == 2
|
|
453
450
|
assert out[0] is False
|
|
454
451
|
|
|
455
|
-
@patch("pyinfra.connectors.util.getpass")
|
|
456
|
-
@patch("pyinfra.connectors.ssh.SSHClient")
|
|
457
|
-
def test_run_shell_command_sudo_password_prompt(
|
|
458
|
-
self,
|
|
459
|
-
fake_ssh_client,
|
|
460
|
-
fake_getpass,
|
|
461
|
-
):
|
|
462
|
-
fake_ssh = MagicMock()
|
|
463
|
-
fake_stdout = MagicMock()
|
|
464
|
-
fake_ssh.exec_command.return_value = MagicMock(), fake_stdout, MagicMock()
|
|
465
|
-
|
|
466
|
-
fake_ssh_client.return_value = fake_ssh
|
|
467
|
-
fake_getpass.return_value = "password"
|
|
468
|
-
|
|
469
|
-
inventory = make_inventory(hosts=("somehost",))
|
|
470
|
-
State(inventory, Config())
|
|
471
|
-
host = inventory.get_host("somehost")
|
|
472
|
-
host.connect()
|
|
473
|
-
|
|
474
|
-
command = "echo Šablony"
|
|
475
|
-
fake_stdout.__iter__.return_value = ["/tmp/pyinfra-sudo-askpass-XXXXXXXXXXXX"]
|
|
476
|
-
fake_stdout.channel.recv_exit_status.return_value = 0
|
|
477
|
-
|
|
478
|
-
out = host.run_shell_command(command, sudo=True, use_sudo_password=True, print_output=True)
|
|
479
|
-
assert len(out) == 3
|
|
480
|
-
|
|
481
|
-
status, stdout, stderr = out
|
|
482
|
-
assert status is True
|
|
483
|
-
|
|
484
|
-
fake_ssh.exec_command.assert_called_with(
|
|
485
|
-
(
|
|
486
|
-
"env SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-XXXXXXXXXXXX "
|
|
487
|
-
"PYINFRA_SUDO_PASSWORD=password "
|
|
488
|
-
"sudo -H -A -k sh -c 'echo Šablony'"
|
|
489
|
-
),
|
|
490
|
-
get_pty=False,
|
|
491
|
-
)
|
|
492
|
-
|
|
493
452
|
@patch("pyinfra.connectors.util.getpass")
|
|
494
453
|
@patch("pyinfra.connectors.ssh.SSHClient")
|
|
495
454
|
def test_run_shell_command_sudo_password_automatic_prompt(
|
|
@@ -524,10 +483,10 @@ class TestSSHConnector(TestCase):
|
|
|
524
483
|
second_fake_stdout.channel.recv_exit_status.return_value = 0
|
|
525
484
|
third_fake_stdout.channel.recv_exit_status.return_value = 0
|
|
526
485
|
|
|
527
|
-
out = host.run_shell_command(command,
|
|
528
|
-
assert len(out) ==
|
|
486
|
+
out = host.run_shell_command(command, _sudo=True, print_output=True)
|
|
487
|
+
assert len(out) == 2
|
|
529
488
|
|
|
530
|
-
status,
|
|
489
|
+
status, output = out
|
|
531
490
|
assert status is True
|
|
532
491
|
|
|
533
492
|
fake_ssh.exec_command.assert_any_call(("sudo -H -n sh -c 'echo Šablony'"), get_pty=False)
|
|
@@ -545,13 +504,13 @@ class TestSSHConnector(TestCase):
|
|
|
545
504
|
#
|
|
546
505
|
|
|
547
506
|
@patch("pyinfra.connectors.ssh.SSHClient")
|
|
548
|
-
@patch("pyinfra.connectors.util.
|
|
507
|
+
@patch("pyinfra.connectors.util.getpass")
|
|
549
508
|
def test_run_shell_command_retry_for_sudo_password(
|
|
550
509
|
self,
|
|
551
|
-
|
|
510
|
+
fake_getpass,
|
|
552
511
|
fake_ssh_client,
|
|
553
512
|
):
|
|
554
|
-
|
|
513
|
+
fake_getpass.return_value = "PASSWORD"
|
|
555
514
|
|
|
556
515
|
fake_ssh = MagicMock()
|
|
557
516
|
fake_stdin = MagicMock()
|
|
@@ -571,13 +530,13 @@ class TestSSHConnector(TestCase):
|
|
|
571
530
|
return_values = [1, 0] # return 0 on the second call
|
|
572
531
|
fake_stdout.channel.recv_exit_status.side_effect = lambda: return_values.pop(0)
|
|
573
532
|
|
|
574
|
-
out = host.run_shell_command(command)
|
|
575
|
-
assert len(out) ==
|
|
533
|
+
out = host.run_shell_command(command, _sudo=True)
|
|
534
|
+
assert len(out) == 2
|
|
576
535
|
assert out[0] is True
|
|
577
|
-
assert
|
|
536
|
+
assert fake_getpass.called
|
|
578
537
|
fake_ssh.exec_command.assert_called_with(
|
|
579
538
|
"env SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-XXXXXXXXXXXX "
|
|
580
|
-
"PYINFRA_SUDO_PASSWORD=PASSWORD sh -c 'echo hi'",
|
|
539
|
+
"PYINFRA_SUDO_PASSWORD=PASSWORD sudo -H -A -k sh -c 'echo hi'",
|
|
581
540
|
get_pty=False,
|
|
582
541
|
)
|
|
583
542
|
|
|
@@ -624,8 +583,8 @@ class TestSSHConnector(TestCase):
|
|
|
624
583
|
"not-a-file",
|
|
625
584
|
"not another file",
|
|
626
585
|
print_output=True,
|
|
627
|
-
|
|
628
|
-
|
|
586
|
+
_sudo=True,
|
|
587
|
+
_sudo_user="ubuntu",
|
|
629
588
|
)
|
|
630
589
|
|
|
631
590
|
assert status is True
|
|
@@ -675,8 +634,8 @@ class TestSSHConnector(TestCase):
|
|
|
675
634
|
"not-a-file",
|
|
676
635
|
"not another file",
|
|
677
636
|
print_output=True,
|
|
678
|
-
|
|
679
|
-
|
|
637
|
+
_doas=True,
|
|
638
|
+
_doas_user="ubuntu",
|
|
680
639
|
)
|
|
681
640
|
|
|
682
641
|
assert status is True
|
|
@@ -726,7 +685,7 @@ class TestSSHConnector(TestCase):
|
|
|
726
685
|
"not-a-file",
|
|
727
686
|
"not-another-file",
|
|
728
687
|
print_output=True,
|
|
729
|
-
|
|
688
|
+
_su_user="centos",
|
|
730
689
|
)
|
|
731
690
|
|
|
732
691
|
assert status is False
|
|
@@ -763,7 +722,7 @@ class TestSSHConnector(TestCase):
|
|
|
763
722
|
"not-a-file",
|
|
764
723
|
"not-another-file",
|
|
765
724
|
print_output=True,
|
|
766
|
-
|
|
725
|
+
_su_user="centos",
|
|
767
726
|
)
|
|
768
727
|
|
|
769
728
|
assert status is False
|
|
@@ -808,8 +767,8 @@ class TestSSHConnector(TestCase):
|
|
|
808
767
|
"not-a-file",
|
|
809
768
|
"not another file",
|
|
810
769
|
print_output=True,
|
|
811
|
-
|
|
812
|
-
|
|
770
|
+
_sudo=True,
|
|
771
|
+
_sudo_user="ubuntu",
|
|
813
772
|
remote_temp_filename="/a-different-tempfile",
|
|
814
773
|
)
|
|
815
774
|
|
|
@@ -865,8 +824,8 @@ class TestSSHConnector(TestCase):
|
|
|
865
824
|
"not-a-file",
|
|
866
825
|
"not-another-file",
|
|
867
826
|
print_output=True,
|
|
868
|
-
|
|
869
|
-
|
|
827
|
+
_sudo=True,
|
|
828
|
+
_sudo_user="ubuntu",
|
|
870
829
|
)
|
|
871
830
|
|
|
872
831
|
assert status is True
|
|
@@ -876,7 +835,7 @@ class TestSSHConnector(TestCase):
|
|
|
876
835
|
call(
|
|
877
836
|
(
|
|
878
837
|
"sudo -H -n -u ubuntu sh -c 'cp not-a-file "
|
|
879
|
-
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r
|
|
838
|
+
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r /tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508'" # noqa
|
|
880
839
|
),
|
|
881
840
|
get_pty=False,
|
|
882
841
|
),
|
|
@@ -910,8 +869,8 @@ class TestSSHConnector(TestCase):
|
|
|
910
869
|
"not-a-file",
|
|
911
870
|
"not-another-file",
|
|
912
871
|
print_output=True,
|
|
913
|
-
|
|
914
|
-
|
|
872
|
+
_sudo=True,
|
|
873
|
+
_sudo_user="ubuntu",
|
|
915
874
|
)
|
|
916
875
|
|
|
917
876
|
assert status is False
|
|
@@ -921,7 +880,7 @@ class TestSSHConnector(TestCase):
|
|
|
921
880
|
call(
|
|
922
881
|
(
|
|
923
882
|
"sudo -H -n -u ubuntu sh -c 'cp not-a-file "
|
|
924
|
-
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r
|
|
883
|
+
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r /tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508'" # noqa
|
|
925
884
|
),
|
|
926
885
|
get_pty=False,
|
|
927
886
|
),
|
|
@@ -946,8 +905,8 @@ class TestSSHConnector(TestCase):
|
|
|
946
905
|
"not-a-file",
|
|
947
906
|
"not-another-file",
|
|
948
907
|
print_output=True,
|
|
949
|
-
|
|
950
|
-
|
|
908
|
+
_sudo=True,
|
|
909
|
+
_sudo_user="ubuntu",
|
|
951
910
|
)
|
|
952
911
|
|
|
953
912
|
assert status is False
|
|
@@ -957,7 +916,7 @@ class TestSSHConnector(TestCase):
|
|
|
957
916
|
call(
|
|
958
917
|
(
|
|
959
918
|
"sudo -H -n -u ubuntu sh -c 'cp not-a-file "
|
|
960
|
-
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r
|
|
919
|
+
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r /tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508'" # noqa
|
|
961
920
|
),
|
|
962
921
|
get_pty=False,
|
|
963
922
|
),
|
|
@@ -994,7 +953,7 @@ class TestSSHConnector(TestCase):
|
|
|
994
953
|
"not-a-file",
|
|
995
954
|
"not-another-file",
|
|
996
955
|
print_output=True,
|
|
997
|
-
|
|
956
|
+
_su_user="centos",
|
|
998
957
|
)
|
|
999
958
|
|
|
1000
959
|
assert status is True
|
|
@@ -1005,7 +964,7 @@ class TestSSHConnector(TestCase):
|
|
|
1005
964
|
(
|
|
1006
965
|
"su centos -c 'sh -c '\"'\"'cp not-a-file "
|
|
1007
966
|
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508 && chmod +r "
|
|
1008
|
-
"
|
|
967
|
+
"/tmp/pyinfra-e9c0d3c8ffca943daa0e75511b0a09c84b59c508'\"'\"''"
|
|
1009
968
|
),
|
|
1010
969
|
get_pty=False,
|
|
1011
970
|
),
|
|
@@ -3,16 +3,10 @@ from unittest import TestCase
|
|
|
3
3
|
from unittest.mock import patch
|
|
4
4
|
|
|
5
5
|
from pyinfra.api.exceptions import InventoryError
|
|
6
|
-
from pyinfra.connectors.terraform import
|
|
6
|
+
from pyinfra.connectors.terraform import TerraformInventoryConnector
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
10
|
-
def test_make_names_data_no_output_key(self):
|
|
11
|
-
with self.assertRaises(InventoryError) as context:
|
|
12
|
-
list(make_names_data())
|
|
13
|
-
|
|
14
|
-
assert context.exception.args[0] == "No Terraform output key!"
|
|
15
|
-
|
|
9
|
+
class TestTerraformConnector(TestCase):
|
|
16
10
|
@patch("pyinfra.connectors.terraform.local.shell")
|
|
17
11
|
def test_make_names_data_no_output(self, fake_shell):
|
|
18
12
|
fake_shell.return_value = json.dumps(
|
|
@@ -24,7 +18,7 @@ class TestVagrantConnector(TestCase):
|
|
|
24
18
|
)
|
|
25
19
|
|
|
26
20
|
with self.assertRaises(InventoryError) as context:
|
|
27
|
-
list(make_names_data("output_key"))
|
|
21
|
+
list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
28
22
|
|
|
29
23
|
assert (
|
|
30
24
|
context.exception.args[0]
|
|
@@ -36,7 +30,7 @@ class TestVagrantConnector(TestCase):
|
|
|
36
30
|
fake_shell.return_value = json.dumps({"output_key": "wrongvalue"})
|
|
37
31
|
|
|
38
32
|
with self.assertRaises(InventoryError) as context:
|
|
39
|
-
list(make_names_data("output_key"))
|
|
33
|
+
list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
40
34
|
|
|
41
35
|
assert (
|
|
42
36
|
context.exception.args[0]
|
|
@@ -48,7 +42,7 @@ class TestVagrantConnector(TestCase):
|
|
|
48
42
|
fake_shell.return_value = json.dumps({"output_key": [None]})
|
|
49
43
|
|
|
50
44
|
with self.assertRaises(InventoryError) as context:
|
|
51
|
-
list(make_names_data("output_key"))
|
|
45
|
+
list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
52
46
|
|
|
53
47
|
assert (
|
|
54
48
|
context.exception.args[0]
|
|
@@ -58,7 +52,7 @@ class TestVagrantConnector(TestCase):
|
|
|
58
52
|
@patch("pyinfra.connectors.terraform.local.shell")
|
|
59
53
|
def test_make_names_data(self, fake_shell):
|
|
60
54
|
fake_shell.return_value = json.dumps({"output_key": ["somehost"]})
|
|
61
|
-
data = list(make_names_data("output_key"))
|
|
55
|
+
data = list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
62
56
|
|
|
63
57
|
assert data == [
|
|
64
58
|
(
|
|
@@ -71,7 +65,7 @@ class TestVagrantConnector(TestCase):
|
|
|
71
65
|
@patch("pyinfra.connectors.terraform.local.shell")
|
|
72
66
|
def test_make_names_data_nested(self, fake_shell):
|
|
73
67
|
fake_shell.return_value = json.dumps({"output_key": {"nested_key": ["somehost"]}})
|
|
74
|
-
data = list(make_names_data("output_key.nested_key"))
|
|
68
|
+
data = list(TerraformInventoryConnector.make_names_data("output_key.nested_key"))
|
|
75
69
|
|
|
76
70
|
assert data == [
|
|
77
71
|
(
|
|
@@ -88,7 +82,7 @@ class TestVagrantConnector(TestCase):
|
|
|
88
82
|
"ssh_hostname": "hostname",
|
|
89
83
|
}
|
|
90
84
|
fake_shell.return_value = json.dumps({"output_key": [host]})
|
|
91
|
-
data = list(make_names_data("output_key"))
|
|
85
|
+
data = list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
92
86
|
|
|
93
87
|
assert data == [
|
|
94
88
|
(
|
|
@@ -106,7 +100,7 @@ class TestVagrantConnector(TestCase):
|
|
|
106
100
|
fake_shell.return_value = json.dumps({"output_key": [host]})
|
|
107
101
|
|
|
108
102
|
with self.assertRaises(InventoryError) as context:
|
|
109
|
-
list(make_names_data("output_key"))
|
|
103
|
+
list(TerraformInventoryConnector.make_names_data("output_key"))
|
|
110
104
|
|
|
111
105
|
assert (
|
|
112
106
|
context.exception.args[0]
|