pyinfra 3.3__py2.py3-none-any.whl → 3.4__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 (47) hide show
  1. pyinfra/api/arguments.py +8 -16
  2. pyinfra/api/deploy.py +1 -1
  3. pyinfra/api/facts.py +10 -26
  4. pyinfra/api/host.py +10 -4
  5. pyinfra/api/inventory.py +5 -2
  6. pyinfra/api/operation.py +1 -1
  7. pyinfra/api/util.py +20 -6
  8. pyinfra/connectors/docker.py +117 -38
  9. pyinfra/connectors/dockerssh.py +1 -0
  10. pyinfra/connectors/local.py +1 -0
  11. pyinfra/connectors/ssh.py +1 -0
  12. pyinfra/connectors/sshuserclient/client.py +5 -5
  13. pyinfra/connectors/terraform.py +3 -0
  14. pyinfra/connectors/vagrant.py +3 -0
  15. pyinfra/context.py +14 -5
  16. pyinfra/facts/brew.py +1 -0
  17. pyinfra/facts/docker.py +6 -2
  18. pyinfra/facts/git.py +10 -0
  19. pyinfra/facts/hardware.py +1 -1
  20. pyinfra/facts/opkg.py +1 -0
  21. pyinfra/facts/server.py +81 -23
  22. pyinfra/facts/systemd.py +1 -1
  23. pyinfra/operations/crontab.py +7 -5
  24. pyinfra/operations/docker.py +2 -0
  25. pyinfra/operations/files.py +64 -21
  26. pyinfra/operations/flatpak.py +17 -2
  27. pyinfra/operations/git.py +6 -2
  28. pyinfra/operations/server.py +34 -24
  29. pyinfra/operations/util/docker.py +4 -0
  30. pyinfra/operations/util/files.py +44 -3
  31. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/METADATA +5 -4
  32. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/RECORD +47 -47
  33. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/entry_points.txt +1 -0
  34. pyinfra_cli/inventory.py +1 -1
  35. pyinfra_cli/main.py +4 -2
  36. tests/test_api/test_api_arguments.py +25 -20
  37. tests/test_api/test_api_facts.py +28 -15
  38. tests/test_api/test_api_operations.py +43 -44
  39. tests/test_cli/test_cli.py +17 -17
  40. tests/test_cli/test_cli_inventory.py +4 -4
  41. tests/test_cli/test_context_objects.py +26 -26
  42. tests/test_connectors/test_docker.py +83 -43
  43. tests/test_connectors/test_ssh.py +153 -132
  44. tests/test_connectors/test_sshuserclient.py +10 -5
  45. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/LICENSE.md +0 -0
  46. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/WHEEL +0 -0
  47. {pyinfra-3.3.dist-info → pyinfra-3.4.dist-info}/top_level.txt +0 -0
@@ -11,26 +11,13 @@ from pyinfra.connectors.util import make_unix_command
11
11
  from ..util import make_inventory
12
12
 
13
13
 
14
- def fake_docker_shell(command, splitlines=None):
15
- if command == "docker run -d not-an-image tail -f /dev/null":
16
- return ["containerid"]
17
-
18
- if command == "docker commit containerid":
19
- return ["sha256:blahsomerandomstringdata"]
14
+ class TestContainerConnector(TestCase):
15
+ # we use this class as a template to prevent the decorators from being invoked twice on
16
+ # the podman test class (since it needs to override fake_docker_shell)
17
+ __test__ = False # this class should not be tested.
18
+ cli_cmd = "docker"
19
+ connector_name = "docker"
20
20
 
21
- if command == "docker rm -f containerid":
22
- return []
23
-
24
- raise PyinfraError("Invalid command: {0}".format(command))
25
-
26
-
27
- @patch("pyinfra.connectors.docker.local.shell", fake_docker_shell)
28
- @patch("pyinfra.connectors.docker.mkstemp", lambda: (None, "__tempfile__"))
29
- @patch("pyinfra.connectors.docker.os.remove", lambda f: None)
30
- @patch("pyinfra.connectors.docker.os.close", lambda f: None)
31
- @patch("pyinfra.connectors.docker.open", mock_open(read_data="test!"), create=True)
32
- @patch("pyinfra.api.util.open", mock_open(read_data="test!"), create=True)
33
- class TestDockerConnector(TestCase):
34
21
  def setUp(self):
35
22
  self.fake_popen_patch = patch("pyinfra.connectors.util.Popen")
36
23
  self.fake_popen_mock = self.fake_popen_patch.start()
@@ -40,46 +27,46 @@ class TestDockerConnector(TestCase):
40
27
 
41
28
  def test_missing_image(self):
42
29
  with self.assertRaises(InventoryError):
43
- make_inventory(hosts=("@docker",))
30
+ make_inventory(hosts=(f"@{self.connector_name}",))
44
31
 
45
32
  def test_user_provided_container_id(self):
46
33
  inventory = make_inventory(
47
- hosts=(("@docker/not-an-image", {"docker_container_id": "abc"}),),
34
+ hosts=((f"@{self.connector_name}/not-an-image", {"docker_container_id": "abc"}),),
48
35
  )
49
36
  State(inventory, Config())
50
- host = inventory.get_host("@docker/not-an-image")
37
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
51
38
  host.connect()
52
39
  assert host.data.docker_container_id == "abc"
53
40
 
54
41
  def test_connect_all(self):
55
- inventory = make_inventory(hosts=("@docker/not-an-image",))
42
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
56
43
  state = State(inventory, Config())
57
44
  connect_all(state)
58
45
  assert len(state.active_hosts) == 1
59
46
 
60
47
  def test_connect_all_error(self):
61
- inventory = make_inventory(hosts=("@docker/a-broken-image",))
48
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/a-broken-image",))
62
49
  state = State(inventory, Config())
63
50
 
64
51
  with self.assertRaises(PyinfraError):
65
52
  connect_all(state)
66
53
 
67
54
  def test_connect_disconnect_host(self):
68
- inventory = make_inventory(hosts=("@docker/not-an-image",))
55
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
69
56
  state = State(inventory, Config())
70
- host = inventory.get_host("@docker/not-an-image")
57
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
71
58
  host.connect(reason=True)
72
59
  assert len(state.active_hosts) == 0
73
60
  host.disconnect()
74
61
 
75
62
  def test_run_shell_command(self):
76
- inventory = make_inventory(hosts=("@docker/not-an-image",))
63
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
77
64
  State(inventory, Config())
78
65
 
79
66
  command = "echo hi"
80
67
  self.fake_popen_mock().returncode = 0
81
68
 
82
- host = inventory.get_host("@docker/not-an-image")
69
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
83
70
  host.connect()
84
71
  out = host.run_shell_command(
85
72
  command,
@@ -92,7 +79,7 @@ class TestDockerConnector(TestCase):
92
79
 
93
80
  command = make_unix_command(command).get_raw_value()
94
81
  command = shlex.quote(command)
95
- docker_command = "docker exec -it containerid sh -c {0}".format(command)
82
+ docker_command = f"{self.cli_cmd} exec -it containerid sh -c {command}"
96
83
  shell_command = make_unix_command(docker_command).get_raw_value()
97
84
 
98
85
  self.fake_popen_mock.assert_called_with(
@@ -104,34 +91,34 @@ class TestDockerConnector(TestCase):
104
91
  )
105
92
 
106
93
  def test_run_shell_command_success_exit_codes(self):
107
- inventory = make_inventory(hosts=("@docker/not-an-image",))
94
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
108
95
  State(inventory, Config())
109
96
 
110
97
  command = "echo hi"
111
98
  self.fake_popen_mock().returncode = 1
112
99
 
113
- host = inventory.get_host("@docker/not-an-image")
100
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
114
101
  host.connect()
115
102
  out = host.run_shell_command(command, _success_exit_codes=[1])
116
103
  assert out[0] is True
117
104
 
118
105
  def test_run_shell_command_error(self):
119
- inventory = make_inventory(hosts=("@docker/not-an-image",))
106
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
120
107
  state = State(inventory, Config())
121
108
 
122
109
  command = "echo hi"
123
110
  self.fake_popen_mock().returncode = 1
124
111
 
125
- host = inventory.get_host("@docker/not-an-image")
112
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
126
113
  host.connect(state)
127
114
  out = host.run_shell_command(command)
128
115
  assert out[0] is False
129
116
 
130
117
  def test_put_file(self):
131
- inventory = make_inventory(hosts=("@docker/not-an-image",))
118
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
132
119
  State(inventory, Config())
133
120
 
134
- host = inventory.get_host("@docker/not-an-image")
121
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
135
122
  host.connect()
136
123
 
137
124
  fake_process = MagicMock(returncode=0)
@@ -140,7 +127,7 @@ class TestDockerConnector(TestCase):
140
127
  host.put_file("not-a-file", "not-another-file", print_output=True)
141
128
 
142
129
  self.fake_popen_mock.assert_called_with(
143
- "sh -c 'docker cp __tempfile__ containerid:not-another-file'",
130
+ f"sh -c '{self.cli_cmd} cp __tempfile__ containerid:not-another-file'",
144
131
  shell=True,
145
132
  stdout=PIPE,
146
133
  stderr=PIPE,
@@ -148,10 +135,10 @@ class TestDockerConnector(TestCase):
148
135
  )
149
136
 
150
137
  def test_put_file_error(self):
151
- inventory = make_inventory(hosts=("@docker/not-an-image",))
138
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
152
139
  State(inventory, Config())
153
140
 
154
- host = inventory.get_host("@docker/not-an-image")
141
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
155
142
  host.connect()
156
143
 
157
144
  fake_process = MagicMock(returncode=1)
@@ -161,10 +148,10 @@ class TestDockerConnector(TestCase):
161
148
  host.put_file("not-a-file", "not-another-file", print_output=True)
162
149
 
163
150
  def test_get_file(self):
164
- inventory = make_inventory(hosts=("@docker/not-an-image",))
151
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
165
152
  State(inventory, Config())
166
153
 
167
- host = inventory.get_host("@docker/not-an-image")
154
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
168
155
  host.connect()
169
156
 
170
157
  fake_process = MagicMock(returncode=0)
@@ -173,7 +160,7 @@ class TestDockerConnector(TestCase):
173
160
  host.get_file("not-a-file", "not-another-file", print_output=True)
174
161
 
175
162
  self.fake_popen_mock.assert_called_with(
176
- "sh -c 'docker cp containerid:not-a-file __tempfile__'",
163
+ f"sh -c '{self.cli_cmd} cp containerid:not-a-file __tempfile__'",
177
164
  shell=True,
178
165
  stdout=PIPE,
179
166
  stderr=PIPE,
@@ -181,10 +168,10 @@ class TestDockerConnector(TestCase):
181
168
  )
182
169
 
183
170
  def test_get_file_error(self):
184
- inventory = make_inventory(hosts=("@docker/not-an-image",))
171
+ inventory = make_inventory(hosts=(f"@{self.connector_name}/not-an-image",))
185
172
  State(inventory, Config())
186
173
 
187
- host = inventory.get_host("@docker/not-an-image")
174
+ host = inventory.get_host(f"@{self.connector_name}/not-an-image")
188
175
  host.connect()
189
176
 
190
177
  fake_process = MagicMock(returncode=1)
@@ -192,3 +179,56 @@ class TestDockerConnector(TestCase):
192
179
 
193
180
  with self.assertRaises(IOError):
194
181
  host.get_file("not-a-file", "not-another-file", print_output=True)
182
+
183
+
184
+ # Reuse the container testing code for docker and podman
185
+
186
+
187
+ def fake_docker_shell(command, splitlines=None):
188
+ if command == "docker run -d not-an-image tail -f /dev/null":
189
+ return ["containerid"]
190
+
191
+ if command == "docker commit containerid":
192
+ return ["sha256:blahsomerandomstringdata"]
193
+
194
+ if command == "docker rm -f containerid":
195
+ return []
196
+
197
+ raise PyinfraError("Invalid command: {0}".format(command))
198
+
199
+
200
+ @patch("pyinfra.connectors.docker.local.shell", fake_docker_shell)
201
+ @patch("pyinfra.connectors.docker.mkstemp", lambda: (None, "__tempfile__"))
202
+ @patch("pyinfra.connectors.docker.os.remove", lambda f: None)
203
+ @patch("pyinfra.connectors.docker.os.close", lambda f: None)
204
+ @patch("pyinfra.connectors.docker.open", mock_open(read_data="test!"), create=True)
205
+ @patch("pyinfra.api.util.open", mock_open(read_data="test!"), create=True)
206
+ class TestDocker2Connector(TestContainerConnector):
207
+ __test__ = True
208
+ cli_cmd = "docker"
209
+ connector_name = "docker"
210
+
211
+
212
+ def fake_podman_shell(command, splitlines=None):
213
+ if command == "podman run -d not-an-image tail -f /dev/null":
214
+ return ["containerid"]
215
+
216
+ if command == "podman commit containerid":
217
+ return ["sha256:blahsomerandomstringdata"]
218
+
219
+ if command == "podman rm -f containerid":
220
+ return []
221
+
222
+ raise PyinfraError("Invalid command: {0}".format(command))
223
+
224
+
225
+ @patch("pyinfra.connectors.docker.local.shell", fake_podman_shell)
226
+ @patch("pyinfra.connectors.docker.mkstemp", lambda: (None, "__tempfile__"))
227
+ @patch("pyinfra.connectors.docker.os.remove", lambda f: None)
228
+ @patch("pyinfra.connectors.docker.os.close", lambda f: None)
229
+ @patch("pyinfra.connectors.docker.open", mock_open(read_data="test!"), create=True)
230
+ @patch("pyinfra.api.util.open", mock_open(read_data="test!"), create=True)
231
+ class TestPodmanConnector(TestContainerConnector):
232
+ __test__ = True
233
+ cli_cmd = "podman"
234
+ connector_name = "podman"