ceph-devstack 0.1.0__py3-none-any.whl → 0.2.0__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.
ceph_devstack/host.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import json
2
3
  import logging
3
4
  import os
4
5
  import pathlib
@@ -74,12 +75,26 @@ class Host:
74
75
 
75
76
  def os_type(self) -> str:
76
77
  if not hasattr(self, "_os_type"):
77
- proc = self.run(["bash", "-c", ". /etc/os-release && echo $ID"])
78
- assert proc.stdout is not None
79
- assert proc.wait() == 0, "is /etc/os-release missing?"
80
- self._os_type = proc.stdout.read().decode().strip().lower()
78
+ proc = self.run(["uname"])
79
+ assert proc.wait() == 0, "uname doesn't work?!"
80
+ if (uname_str := proc.stdout.read().decode().strip().lower()) == "linux":
81
+ proc = self.run(["bash", "-c", ". /etc/os-release && echo $ID"])
82
+ assert proc.stdout is not None
83
+ assert proc.wait() == 0, "is /etc/os-release missing?"
84
+ self._os_type = proc.stdout.read().decode().strip().lower()
85
+ else:
86
+ self._os_type = uname_str
81
87
  return self._os_type
82
88
 
89
+ def package_manager(self) -> str | None:
90
+ if self.os_type in ["centos", "rhel", "alma", "rocky", "fedora"]:
91
+ return "dnf"
92
+ elif self.os_type in ["debian", "ubuntu"]:
93
+ return "apt"
94
+ elif self.os_type == "darwin":
95
+ return "brew"
96
+ raise RuntimeError("Can't determine package manager")
97
+
83
98
  async def podman_info(self, force: bool = False) -> Dict:
84
99
  if force or not hasattr(self, "_podman_info"):
85
100
  proc = await self.arun(["podman", "info"])
@@ -89,6 +104,13 @@ class Host:
89
104
  self._podman_info = yaml.safe_load(stdout.decode().strip())
90
105
  return self._podman_info
91
106
 
107
+ async def podman_machine_info(self) -> List[Dict]:
108
+ proc = await self.arun(["podman", "machine", "list", "--format", "json"])
109
+ assert proc.stdout is not None
110
+ await proc.wait()
111
+ stdout = await proc.stdout.read()
112
+ return json.loads(stdout)
113
+
92
114
  async def selinux_enforcing(self) -> bool:
93
115
  proc = await host.arun(["cat", "/sys/fs/selinux/enforce"])
94
116
  assert proc.stdout is not None
@@ -1,5 +1,4 @@
1
1
  import shlex
2
- import sys
3
2
 
4
3
  from pathlib import Path
5
4
  from packaging.version import parse as parse_version, Version
@@ -40,7 +39,7 @@ class FixableRequirement(Requirement):
40
39
 
41
40
  async def fix(self) -> bool:
42
41
  assert self.fix_cmd, "Attempted to fix without a fix command"
43
- proc = await self.host.arun(self.fix_cmd)
42
+ proc = await self.host.arun(self.fix_cmd, stream_output=True)
44
43
  return await proc.wait() == 0
45
44
 
46
45
 
@@ -48,36 +47,49 @@ class LocalRequirement(Requirement):
48
47
  host = local_host
49
48
 
50
49
 
51
- class PodmanPlatform(Requirement):
50
+ class LocalFixableRequirement(FixableRequirement):
51
+ host = local_host
52
+
53
+
54
+ class PodmanPlatform(LocalFixableRequirement):
55
+ suggest_msg = "podman not found"
56
+
57
+ @property
58
+ def fix_cmd(self):
59
+ host_os = self.host.os_type()
60
+ if host_os == "darwin":
61
+ return ["brew", "install", "podman"]
62
+ return ["sudo", host.package_manager(), "install", "-y", "podman"]
63
+
52
64
  async def check(self):
53
- result = False
54
65
  try:
55
- podman_info = await self.host.podman_info()
66
+ await self.host.podman_info()
67
+ return True
56
68
  except FileNotFoundError:
57
69
  logger.error("podman not found. Try: dnf install podman")
58
70
  return False
59
- try:
60
- host_os = (
61
- podman_info["host"].get("Os") or podman_info["host"]["os"]
62
- ).lower()
63
- if host_os == "linux":
64
- result = True
65
- except KeyError:
66
- host_os = sys.platform.lower()
67
- result = False
68
- if sys.platform == "darwin":
69
- logger.error(
70
- "The podman machine (VM) is not running. "
71
- "Try: podman machine init --now"
72
- )
73
- else:
74
- logger.error(
75
- "Unknown error trying to query podman. Is podman installed?"
76
- )
77
- return result
78
- if host_os != "linux":
79
- logger.error("The platform '{host_os}' is not currently supported.")
80
- return result
71
+
72
+
73
+ class PodmanMachinePresent(FixableRequirement):
74
+ suggest_msg = "podman machine (VM) not present"
75
+ fix_cmd = ["podman", "machine", "init", "--now"]
76
+
77
+ async def check(self):
78
+ machine_infos = await host.podman_machine_info()
79
+ if machine_infos and (machine_info := machine_infos[-1]):
80
+ return machine_info.get("Created") is not None
81
+ return False
82
+
83
+
84
+ class PodmanMachineRunning(LocalFixableRequirement):
85
+ suggest_msg = "podman machine (VM) not running"
86
+ fix_cmd = ["podman", "machine", "start"]
87
+
88
+ async def check(self):
89
+ machine_infos = await host.podman_machine_info()
90
+ if machine_infos and (machine_info := machine_infos[-1]):
91
+ return machine_info.get("Running", False)
92
+ return False
81
93
 
82
94
 
83
95
  class PodmanGraphDriver(Requirement):
@@ -150,6 +162,12 @@ class PodmanVersion(Requirement):
150
162
 
151
163
 
152
164
  class PodmanRuntime(Requirement):
165
+ @property
166
+ def fix_cmd(self):
167
+ if self.host.os_type() != "darwin":
168
+ return ["sudo", self.host.package_manager(), "install", "-y", "crun"]
169
+ return []
170
+
153
171
  async def check(self):
154
172
  podman_info = await self.host.podman_info()
155
173
  storage_conf_path = podman_info["store"]["configFile"]
@@ -194,22 +212,31 @@ class SysctlValue(FixableRequirement):
194
212
  class PodmanDNSPlugin(FixableRequirement):
195
213
  suggest_msg = "Could not find the podman DNS plugin"
196
214
 
197
- def __init__(self):
215
+ @property
216
+ def dns_plugin_path(self):
217
+ os_type = self.host.os_type()
218
+ if os_type in ["ubuntu", "debian"]:
219
+ return "/usr/lib/cni/dnsname"
220
+ return "/usr/libexec/cni/dnsname"
221
+
222
+ @property
223
+ def check_cmd(self):
224
+ return ["test", "-x", self.dns_plugin_path]
225
+
226
+ @property
227
+ def fix_cmd(self):
198
228
  os_type = self.host.os_type()
199
229
  if os_type == "centos":
200
- dns_plugin_path = "/usr/libexec/cni/dnsname"
201
- self.check_cmd = ["test", "-x", dns_plugin_path]
202
- self.fix_cmd = ["sudo", "dnf", "install", "-y", dns_plugin_path]
230
+ return ["sudo", "dnf", "install", "-y", self.dns_plugin_path]
203
231
  elif os_type in ["ubuntu", "debian"]:
204
- dns_plugin_path = "/usr/lib/cni/dnsname"
205
- self.check_cmd = ["test", "-x", dns_plugin_path]
206
- self.fix_cmd = [
232
+ return [
207
233
  "sudo",
208
234
  "apt",
209
235
  "install",
210
236
  "-y",
211
237
  "golang-github-containernetworking-plugin-dnsname",
212
238
  ]
239
+ return []
213
240
 
214
241
 
215
242
  class FuseOverlayfsPresence(FixableRequirement):
@@ -234,6 +261,11 @@ class AppArmorProfile(FixableRequirement):
234
261
  async def check_requirements():
235
262
  if not await PodmanPlatform().evaluate():
236
263
  return False
264
+ if local_host.os_type() == "darwin":
265
+ if not await PodmanMachinePresent().evaluate():
266
+ return False
267
+ if not await PodmanMachineRunning().evaluate():
268
+ return False
237
269
 
238
270
  result = True
239
271
  # kernel and podman versions for native overlay filesystem
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ceph-devstack
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Run a full teuthology lab on your laptop!
5
5
  Author-email: Zack Cerza <zack@cerza.org>
6
6
  License-Expression: MIT
@@ -5,10 +5,10 @@ ceph_devstack/ceph_devstack.te,sha256=68i9sBb1TAEnCJn2JtyM-ECzPSuZck4vKoymcTbptX
5
5
  ceph_devstack/cli.py,sha256=lSYwXrwfP8D-k60XuwSqhwZSZNKJFFQfvRM-av1rePM,2057
6
6
  ceph_devstack/config.toml,sha256=HsxO3FhwZkHomde69QfElztuN8U1bxk7cQk1_iWB4w0,562
7
7
  ceph_devstack/exec.py,sha256=gn95GEQttB6xgdWXXvTsxUxcQsx9TUu6PC8QVQ0_Y7w,2674
8
- ceph_devstack/host.py,sha256=cShqi4FORP_cFTP2u33BYfhPpI0Nsd-bx9YLNfqBhUA,4556
8
+ ceph_devstack/host.py,sha256=IRLhQaE_jl4VyHLArkqGzYWi3mxT8_sCG6Y7iDol4vU,5456
9
9
  ceph_devstack/logging.conf,sha256=bGlswYcL_fz522y9EoKZOLInrSss8D44glNq0FievFY,521
10
10
  ceph_devstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- ceph_devstack/requirements.py,sha256=NgH0k8qU-cSvuZqp-TsM9CNiki2CsQKGuZM_vCq9SDQ,9192
11
+ ceph_devstack/requirements.py,sha256=7Ashf6qfXW1k-L1Gakj5_Q-fPOBEhMQWnh0hIvtUjh0,9980
12
12
  ceph_devstack/resources/__init__.py,sha256=D0vhJBU9Pqslq7hg2qreW_ZhndcRIOHZVVUA0zAIeDM,3386
13
13
  ceph_devstack/resources/container.py,sha256=suJNOQ9fMRfCnXQwvEZOcg4jnPtrxb-d17a3Y1s1xG0,5388
14
14
  ceph_devstack/resources/misc.py,sha256=iGD_3Xsqako-dOZrHJFEJbMWoQIzy7Q_KkEnkdBb8m0,552
@@ -17,13 +17,13 @@ ceph_devstack/resources/ceph/containers.py,sha256=3QEwkh3I7f3r47SnlnMB-_mU8fYGR0
17
17
  ceph_devstack/resources/ceph/exceptions.py,sha256=C4ldyEA7Cukp-QUOwL-MnQ8kpgMDIQ6r_JQe0E9q4eM,101
18
18
  ceph_devstack/resources/ceph/requirements.py,sha256=ZJt7Eeb5y2bOc7dJN3-15ftAyySi80phD7erBsGdqSU,2691
19
19
  ceph_devstack/resources/ceph/utils.py,sha256=6-1sageEiLMcx53KHo_GKlIjaGw3swoZk8cQ-e-tDP0,1276
20
- ceph_devstack-0.1.0.dist-info/licenses/LICENSE,sha256=bFeYufyeS1qw0W8pkW1Wj09F2itqX7TAGTnA2NIpApU,1067
20
+ ceph_devstack-0.2.0.dist-info/licenses/LICENSE,sha256=bFeYufyeS1qw0W8pkW1Wj09F2itqX7TAGTnA2NIpApU,1067
21
21
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  tests/conftest.py,sha256=qulfsMZz3PyAFMdWQ_VWpOFT9L_BiavRax_yQF2Ne24,128
23
23
  tests/test_config.py,sha256=RLAjt9DAcAo8GQXgv9dc3Ka3hhtongMs6ioz5YQwKhY,4394
24
24
  tests/test_deep_merge.py,sha256=IP9zzCThmhVghl9XjAAiSrKsPdouH3KbEUaKq8n3Soc,2178
25
25
  tests/test_parse_args.py,sha256=2JDAT4Id88Ywl5QmiUHqq5IDGm_j5Yl3Kk7pbl3sOEk,7550
26
- tests/test_requirements_core.py,sha256=9IqpcbnatnFJrjp4_fb1arJ-nNO4KXdWjXNMzNzRjNk,18636
26
+ tests/test_requirements_core.py,sha256=t7dE53E6N3owO1aHd0nLjXGZ9WDGFFUNIQKZQd1jJBY,19985
27
27
  tests/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  tests/resources/test_container.py,sha256=Xc4IGLf0PViSBIhUQXZHZQtRc-uI2R3PyNjU8lpX6BE,9081
29
29
  tests/resources/test_misc.py,sha256=dtOAPngMCTE9bYuYjNuxBiRaxvEibXuBq5VwVsWBdnY,1560
@@ -32,13 +32,13 @@ tests/resources/ceph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
32
32
  tests/resources/ceph/test_cephdevstack_core.py,sha256=2Zopu-3TkXyj1amQbMG1KpsVXyRDJts73e6TLYNyz3Y,18340
33
33
  tests/resources/ceph/test_devstack.py,sha256=PRsEyYy9EKFIiZKkHYZh6vGffIzlZuW9jA9XEt7xz5M,6201
34
34
  tests/resources/ceph/test_env_vars.py,sha256=bLTcEJQJSQp0iiJBunPdGHtVQ94KRWSNEkK8HtXZQn0,2741
35
- tests/resources/ceph/test_requirements_ceph.py,sha256=R3oqC9wu5VXJfa4aWpRYOSPh8wt25RPVuUxhzuyCtSw,9548
35
+ tests/resources/ceph/test_requirements_ceph.py,sha256=VLPHrzt1dLk3RnzjqRY3wyPUQbMspUuW6S_9cAWtpYU,9134
36
36
  tests/resources/ceph/test_ssh_keypair.py,sha256=M8Tc1CY9zb_1WaccMSfnSN35tyjR-CblNtTP0s4OsYU,4019
37
37
  tests/resources/ceph/test_testnode.py,sha256=wiftdOU058z9IKp5LeUNlv81U9XjojRUI0fYt8mrbgg,1253
38
38
  tests/resources/ceph/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  tests/resources/ceph/fixtures/testnode-config.toml,sha256=XaI4VACYHeshb7LLxN3viKBNxOBLOUpPuwlcQJyQO-U,44
40
- ceph_devstack-0.1.0.dist-info/METADATA,sha256=vRtYDGquw7pUJ45MTHe3HGf762f7UDUM-z5L7XxxGw4,6877
41
- ceph_devstack-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
42
- ceph_devstack-0.1.0.dist-info/entry_points.txt,sha256=3cXOGOSb23ATcOZVQFBTY_imM4VFgFddXlYi-m8PA10,57
43
- ceph_devstack-0.1.0.dist-info/top_level.txt,sha256=NzTr-vAk2OWL08T8PsmfqkJZNEuezF5oaiHCMJBhHPM,20
44
- ceph_devstack-0.1.0.dist-info/RECORD,,
40
+ ceph_devstack-0.2.0.dist-info/METADATA,sha256=6QrXrp1vvd4eAAtp8rmKlzPnh6FdyBD9HLBPW-thmjI,6877
41
+ ceph_devstack-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
42
+ ceph_devstack-0.2.0.dist-info/entry_points.txt,sha256=3cXOGOSb23ATcOZVQFBTY_imM4VFgFddXlYi-m8PA10,57
43
+ ceph_devstack-0.2.0.dist-info/top_level.txt,sha256=NzTr-vAk2OWL08T8PsmfqkJZNEuezF5oaiHCMJBhHPM,20
44
+ ceph_devstack-0.2.0.dist-info/RECORD,,
@@ -216,15 +216,11 @@ class TestCephDevStackCheckRequirements:
216
216
  ) as MockLoopCtrlWrite,
217
217
  patch("ceph_devstack.host.host.selinux_enforcing") as mock_selinux,
218
218
  ):
219
- mock_has_sudo = AsyncMock()
220
- mock_has_sudo.evaluate = AsyncMock(return_value=True)
221
- MockHasSudo.return_value = mock_has_sudo
222
- mock_loop_ctrl = AsyncMock()
223
- mock_loop_ctrl.evaluate = AsyncMock(return_value=True)
224
- MockLoopCtrl.return_value = mock_loop_ctrl
225
- mock_loop_ctrl_write = AsyncMock()
226
- mock_loop_ctrl_write.evaluate = AsyncMock(return_value=True)
227
- MockLoopCtrlWrite.return_value = mock_loop_ctrl_write
219
+ MockHasSudo.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
220
+ MockLoopCtrl.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
221
+ MockLoopCtrlWrite.return_value = AsyncMock(
222
+ evaluate=AsyncMock(return_value=True)
223
+ )
228
224
  mock_selinux.return_value = False
229
225
  result = await devstack.check_requirements()
230
226
  assert result is True
@@ -247,15 +243,11 @@ class TestCephDevStackCheckRequirements:
247
243
  patch("ceph_devstack.host.host.selinux_enforcing") as mock_selinux,
248
244
  patch("ceph_devstack.host.host.path_exists") as mock_path_exists,
249
245
  ):
250
- mock_has_sudo = AsyncMock()
251
- mock_has_sudo.evaluate = AsyncMock(return_value=True)
252
- MockHasSudo.return_value = mock_has_sudo
253
- mock_loop_ctrl = AsyncMock()
254
- mock_loop_ctrl.evaluate = AsyncMock(return_value=True)
255
- MockLoopCtrl.return_value = mock_loop_ctrl
256
- mock_loop_ctrl_write = AsyncMock()
257
- mock_loop_ctrl_write.evaluate = AsyncMock(return_value=True)
258
- MockLoopCtrlWrite.return_value = mock_loop_ctrl_write
246
+ MockHasSudo.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
247
+ MockLoopCtrl.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
248
+ MockLoopCtrlWrite.return_value = AsyncMock(
249
+ evaluate=AsyncMock(return_value=True)
250
+ )
259
251
  mock_selinux.return_value = False
260
252
  mock_path_exists.return_value = False
261
253
  result = await devstack.check_requirements()
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import pytest
3
3
  from packaging.version import parse as parse_version
4
- from unittest.mock import AsyncMock, patch
4
+ from unittest.mock import AsyncMock, MagicMock, patch
5
5
 
6
6
 
7
7
  from ceph_devstack import config, requirements
@@ -17,6 +17,11 @@ def req(cls):
17
17
  return cls()
18
18
 
19
19
 
20
+ @pytest.fixture(scope="class", params=["centos", "ubuntu", "debian"])
21
+ def os_type(request):
22
+ return request.param
23
+
24
+
20
25
  class TestRequirement:
21
26
  @pytest.fixture(scope="class")
22
27
  def cls(self):
@@ -113,6 +118,73 @@ class TestLocalRequirement:
113
118
  assert req.host == requirements.local_host
114
119
 
115
120
 
121
+ class TestPodmanPlatform:
122
+ @pytest.fixture(scope="class")
123
+ def cls(self):
124
+ return requirements.PodmanPlatform
125
+
126
+ async def test_podman_present(self, cls):
127
+ with (
128
+ patch(
129
+ "ceph_devstack.requirements.PodmanPlatform.host.podman_info"
130
+ ) as MockPodmanInfo,
131
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
132
+ ):
133
+ MockLocalHost.os_type = MagicMock(return_value="darwin")
134
+ MockPodmanInfo.return_value = {}
135
+ req = cls()
136
+ assert await req.check() is True
137
+
138
+ async def test_podman_missing(self, cls):
139
+ with (
140
+ patch(
141
+ "ceph_devstack.requirements.PodmanPlatform.host.podman_info"
142
+ ) as MockPodmanInfo,
143
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
144
+ ):
145
+ MockLocalHost.os_type = MagicMock(return_value="darwin")
146
+ MockPodmanInfo.side_effect = FileNotFoundError
147
+ req = cls()
148
+ assert await req.check() is False
149
+
150
+
151
+ class TestPodmanMachinePresent:
152
+ @pytest.fixture(scope="class")
153
+ def cls(self):
154
+ return requirements.PodmanMachinePresent
155
+
156
+ @pytest.mark.parametrize(
157
+ "info,success", [[{}, False], [{"Created": "some_timestamp"}, True]]
158
+ )
159
+ async def test_podman_machine_present(self, cls, info, success):
160
+ with patch("ceph_devstack.requirements.host", AsyncMock()) as MockHost:
161
+ MockHost.podman_machine_info = AsyncMock(return_value=[info])
162
+ req = cls()
163
+ assert await req.check() is success
164
+
165
+
166
+ class TestPodmanMachineRunning:
167
+ @pytest.fixture(scope="class")
168
+ def cls(self):
169
+ return requirements.PodmanMachineRunning
170
+
171
+ @pytest.mark.parametrize(
172
+ "info,success",
173
+ [[{}, False], [{"Running": False}, False], [{"Running": True}, True]],
174
+ )
175
+ async def test_podman_machine_running(self, cls, info, success):
176
+ with patch("ceph_devstack.requirements.host", AsyncMock()) as MockHost:
177
+ MockHost.podman_machine_info = AsyncMock(return_value=[info])
178
+ req = cls()
179
+ assert await req.check() is success
180
+
181
+
182
+ class TestPodmanRuntime:
183
+ @pytest.fixture(scope="class")
184
+ def cls(self):
185
+ return requirements.PodmanRuntime
186
+
187
+
116
188
  class TestPodmanVersionInit:
117
189
  @pytest.fixture(scope="class")
118
190
  def cls(self):
@@ -223,10 +295,6 @@ class TestPodmanDNSPluginInit:
223
295
  def cls(self):
224
296
  return requirements.PodmanDNSPlugin
225
297
 
226
- @pytest.fixture(scope="class", params=["centos", "ubuntu", "debian"])
227
- def os_type(self, request):
228
- return request.param
229
-
230
298
  @pytest.fixture(scope="class")
231
299
  def dns_plugin_path(self, os_type):
232
300
  if os_type == "centos":
@@ -281,22 +349,25 @@ class TestCheckRequirements:
281
349
 
282
350
  async def test_check_requirements_returns_false_on_overlay_failure(self):
283
351
  with (
352
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
284
353
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
285
354
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
355
+ patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
356
+ patch("ceph_devstack.requirements.KernelVersionForOverlay") as MockKernel,
357
+ patch("ceph_devstack.requirements.CgroupV2") as MockCgroup,
286
358
  ):
287
- mock_platform = AsyncMock()
288
- mock_platform.evaluate = AsyncMock(return_value=True)
289
- MockPlatform.return_value = mock_platform
290
-
291
- mock_graph = AsyncMock()
292
- mock_graph.evaluate = AsyncMock(return_value=False)
293
- MockGraph.return_value = mock_graph
294
-
359
+ MockLocalHost.os_type = MagicMock(return_value="centos")
360
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
361
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
362
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
363
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
364
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
295
365
  result = await requirements.check_requirements()
296
366
  assert result is False
297
367
 
298
368
  async def test_check_requirements_returns_true_when_all_pass(self):
299
369
  with (
370
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
300
371
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
301
372
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
302
373
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -309,45 +380,24 @@ class TestCheckRequirements:
309
380
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
310
381
  patch("ceph_devstack.requirements.SysctlValue") as MockSysctl,
311
382
  ):
312
- mock_platform = AsyncMock()
313
- mock_platform.evaluate = AsyncMock(return_value=True)
314
- MockPlatform.return_value = mock_platform
315
-
316
- mock_graph = AsyncMock()
317
- mock_graph.evaluate = AsyncMock(return_value=True)
318
- MockGraph.return_value = mock_graph
319
-
320
- mock_version = AsyncMock()
321
- mock_version.evaluate = AsyncMock(return_value=True)
322
- MockVersion.return_value = mock_version
323
-
324
- mock_kernel = AsyncMock()
325
- mock_kernel.evaluate = AsyncMock(return_value=True)
326
- MockKernel.return_value = mock_kernel
327
-
328
- mock_cgroup = AsyncMock()
329
- mock_cgroup.evaluate = AsyncMock(return_value=True)
330
- MockCgroup.return_value = mock_cgroup
331
-
332
- mock_kernel_cgroup = AsyncMock()
333
- mock_kernel_cgroup.evaluate = AsyncMock(return_value=True)
334
- MockKernelCgroup.return_value = mock_kernel_cgroup
335
-
336
- mock_runtime = AsyncMock()
337
- mock_runtime.evaluate = AsyncMock(return_value=True)
338
- MockRuntime.return_value = mock_runtime
339
-
383
+ MockLocalHost.os_type = MagicMock(return_value="centos")
384
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
385
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
386
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
387
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
388
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
389
+ MockKernelCgroup.return_value = AsyncMock(
390
+ evaluate=AsyncMock(return_value=True)
391
+ )
392
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
340
393
  mock_selinux.return_value = False
341
-
342
- mock_sysctl = AsyncMock()
343
- mock_sysctl.evaluate = AsyncMock(return_value=True)
344
- MockSysctl.return_value = mock_sysctl
345
-
394
+ MockSysctl.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
346
395
  result = await requirements.check_requirements()
347
396
  assert result is True
348
397
 
349
398
  async def test_check_requirements_returns_false_on_runtime_failure(self):
350
399
  with (
400
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
351
401
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
352
402
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
353
403
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -359,43 +409,26 @@ class TestCheckRequirements:
359
409
  patch("ceph_devstack.requirements.PodmanRuntime") as MockRuntime,
360
410
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
361
411
  ):
362
- mock_platform = AsyncMock()
363
- mock_platform.evaluate = AsyncMock(return_value=True)
364
- MockPlatform.return_value = mock_platform
365
-
366
- mock_graph = AsyncMock()
367
- mock_graph.evaluate = AsyncMock(return_value=True)
368
- MockGraph.return_value = mock_graph
369
-
370
- mock_version = AsyncMock()
371
- mock_version.evaluate = AsyncMock(return_value=True)
372
- MockVersion.return_value = mock_version
373
-
374
- mock_kernel = AsyncMock()
375
- mock_kernel.evaluate = AsyncMock(return_value=True)
376
- MockKernel.return_value = mock_kernel
377
-
378
- mock_cgroup = AsyncMock()
379
- mock_cgroup.evaluate = AsyncMock(return_value=True)
380
- MockCgroup.return_value = mock_cgroup
381
-
412
+ MockLocalHost.os_type = MagicMock(return_value="centos")
413
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
414
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
415
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
416
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
417
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
382
418
  mock_kernel_cgroup = AsyncMock()
383
419
  mock_kernel_cgroup.evaluate = AsyncMock(return_value=True)
384
420
  MockKernelCgroup.return_value = mock_kernel_cgroup
385
-
386
- mock_runtime = AsyncMock()
387
- mock_runtime.evaluate = AsyncMock(return_value=False)
388
- MockRuntime.return_value = mock_runtime
389
-
421
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
390
422
  mock_selinux.return_value = False
391
-
392
423
  result = await requirements.check_requirements()
393
424
  assert result is False
394
425
 
395
426
  async def test_check_requirements_returns_false_on_selinux_bool_failure(self):
396
427
  with (
428
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
397
429
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
398
430
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
431
+ patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
399
432
  patch("ceph_devstack.requirements.KernelVersionForOverlay") as MockKernel,
400
433
  patch("ceph_devstack.requirements.CgroupV2") as MockCgroup,
401
434
  patch(
@@ -405,46 +438,26 @@ class TestCheckRequirements:
405
438
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
406
439
  patch("ceph_devstack.requirements.SELinuxBoolean") as MockSELinuxBoolean,
407
440
  ):
408
- mock_platform = AsyncMock()
409
- mock_platform.evaluate = AsyncMock(return_value=True)
410
- MockPlatform.return_value = mock_platform
411
-
412
- mock_graph = AsyncMock()
413
- mock_graph.evaluate = AsyncMock(return_value=True)
414
- MockGraph.return_value = mock_graph
415
-
416
- with patch("ceph_devstack.requirements.PodmanVersion") as MockVersion:
417
- mock_version = AsyncMock()
418
- mock_version.evaluate = AsyncMock(return_value=True)
419
- MockVersion.return_value = mock_version
420
-
421
- mock_kernel = AsyncMock()
422
- mock_kernel.evaluate = AsyncMock(return_value=True)
423
- MockKernel.return_value = mock_kernel
424
-
425
- mock_cgroup = AsyncMock()
426
- mock_cgroup.evaluate = AsyncMock(return_value=True)
427
- MockCgroup.return_value = mock_cgroup
428
-
429
- mock_kernel_cgroup = AsyncMock()
430
- mock_kernel_cgroup.evaluate = AsyncMock(return_value=True)
431
- MockKernelCgroup.return_value = mock_kernel_cgroup
432
-
433
- mock_runtime = AsyncMock()
434
- mock_runtime.evaluate = AsyncMock(return_value=True)
435
- MockRuntime.return_value = mock_runtime
436
-
437
- mock_selinux.return_value = True
438
-
439
- mock_sel = AsyncMock()
440
- mock_sel.evaluate = AsyncMock(return_value=False)
441
- MockSELinuxBoolean.return_value = mock_sel
442
-
443
- result = await requirements.check_requirements()
444
- assert result is False
441
+ MockLocalHost.os_type = MagicMock(return_value="centos")
442
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
443
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
444
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
445
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
446
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
447
+ MockKernelCgroup.return_value = AsyncMock(
448
+ evaluate=AsyncMock(return_value=True)
449
+ )
450
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
451
+ mock_selinux.return_value = True
452
+ MockSELinuxBoolean.return_value = AsyncMock(
453
+ evaluate=AsyncMock(return_value=False)
454
+ )
455
+ result = await requirements.check_requirements()
456
+ assert result is False
445
457
 
446
458
  async def test_check_requirements_returns_false_on_sysctl_failure(self):
447
459
  with (
460
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
448
461
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
449
462
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
450
463
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -457,39 +470,17 @@ class TestCheckRequirements:
457
470
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
458
471
  patch("ceph_devstack.requirements.SysctlValue") as MockSysctl,
459
472
  ):
460
- mock_platform = AsyncMock()
461
- mock_platform.evaluate = AsyncMock(return_value=True)
462
- MockPlatform.return_value = mock_platform
463
-
464
- mock_graph = AsyncMock()
465
- mock_graph.evaluate = AsyncMock(return_value=True)
466
- MockGraph.return_value = mock_graph
467
-
468
- mock_version = AsyncMock()
469
- mock_version.evaluate = AsyncMock(return_value=True)
470
- MockVersion.return_value = mock_version
471
-
472
- mock_kernel = AsyncMock()
473
- mock_kernel.evaluate = AsyncMock(return_value=True)
474
- MockKernel.return_value = mock_kernel
475
-
476
- mock_cgroup = AsyncMock()
477
- mock_cgroup.evaluate = AsyncMock(return_value=True)
478
- MockCgroup.return_value = mock_cgroup
479
-
480
- mock_kernel_cgroup = AsyncMock()
481
- mock_kernel_cgroup.evaluate = AsyncMock(return_value=True)
482
- MockKernelCgroup.return_value = mock_kernel_cgroup
483
-
484
- mock_runtime = AsyncMock()
485
- mock_runtime.evaluate = AsyncMock(return_value=True)
486
- MockRuntime.return_value = mock_runtime
487
-
473
+ MockLocalHost.os_type = MagicMock(return_value="centos")
474
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
475
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
476
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
477
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
478
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
479
+ MockKernelCgroup.return_value = AsyncMock(
480
+ evaluate=AsyncMock(return_value=True)
481
+ )
482
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
488
483
  mock_selinux.return_value = False
489
-
490
- mock_sysctl = AsyncMock()
491
- mock_sysctl.evaluate = AsyncMock(return_value=False)
492
- MockSysctl.return_value = mock_sysctl
493
-
484
+ MockSysctl.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
494
485
  result = await requirements.check_requirements()
495
486
  assert result is False