ceph-devstack 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -72,14 +73,29 @@ class Host:
72
73
  self._kernel_version = parse_version(raw_version.split("-")[0])
73
74
  return self._kernel_version
74
75
 
76
+ @property
75
77
  def os_type(self) -> str:
76
78
  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()
79
+ proc = self.run(["uname"])
80
+ assert proc.wait() == 0, "uname doesn't work?!"
81
+ if (uname_str := proc.stdout.read().decode().strip().lower()) == "linux":
82
+ proc = self.run(["bash", "-c", ". /etc/os-release && echo $ID"])
83
+ assert proc.stdout is not None
84
+ assert proc.wait() == 0, "is /etc/os-release missing?"
85
+ self._os_type = proc.stdout.read().decode().strip().lower()
86
+ else:
87
+ self._os_type = uname_str
81
88
  return self._os_type
82
89
 
90
+ def package_manager(self) -> str | None:
91
+ if self.os_type in ["centos", "rhel", "alma", "rocky", "fedora"]:
92
+ return "dnf"
93
+ elif self.os_type in ["debian", "ubuntu"]:
94
+ return "apt"
95
+ elif self.os_type == "darwin":
96
+ return "brew"
97
+ raise RuntimeError("Can't determine package manager")
98
+
83
99
  async def podman_info(self, force: bool = False) -> Dict:
84
100
  if force or not hasattr(self, "_podman_info"):
85
101
  proc = await self.arun(["podman", "info"])
@@ -89,6 +105,13 @@ class Host:
89
105
  self._podman_info = yaml.safe_load(stdout.decode().strip())
90
106
  return self._podman_info
91
107
 
108
+ async def podman_machine_info(self) -> List[Dict]:
109
+ proc = await self.arun(["podman", "machine", "list", "--format", "json"])
110
+ assert proc.stdout is not None
111
+ await proc.wait()
112
+ stdout = await proc.stdout.read()
113
+ return json.loads(stdout)
114
+
92
115
  async def selinux_enforcing(self) -> bool:
93
116
  proc = await host.arun(["cat", "/sys/fs/selinux/enforce"])
94
117
  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):
198
- os_type = self.host.os_type()
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):
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.1
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=w_Hx912y1g62yXkTuPJsw_UdUwxJr_Pbxrj8iZtEP7Y,5470
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=tQIk4TVl-1s5vOBgt5oML6Zk9-ZRtPLzAQ3foBdQpMk,9970
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.1.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=MnhENRBFQkhIYD9sI1HBYBEocqiDBChRw7bOuSI-kPk,20089
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.1.dist-info/METADATA,sha256=0sxnNB5VBwU61eY7AlPi14s0LrsR6qUWGzblLEus7uA,6877
41
+ ceph_devstack-0.2.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
42
+ ceph_devstack-0.2.1.dist-info/entry_points.txt,sha256=3cXOGOSb23ATcOZVQFBTY_imM4VFgFddXlYi-m8PA10,57
43
+ ceph_devstack-0.2.1.dist-info/top_level.txt,sha256=NzTr-vAk2OWL08T8PsmfqkJZNEuezF5oaiHCMJBhHPM,20
44
+ ceph_devstack-0.2.1.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, PropertyMock
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":
@@ -235,7 +303,10 @@ class TestPodmanDNSPluginInit:
235
303
  return "/usr/lib/cni/dnsname"
236
304
 
237
305
  def test_podman_dns_plugin_config(self, cls, os_type, dns_plugin_path):
238
- with patch.object(cls.host, "os_type", return_value=os_type):
306
+ with patch(
307
+ "ceph_devstack.host.Host.os_type", new_callable=PropertyMock
308
+ ) as MockHost:
309
+ MockHost.return_value = os_type
239
310
  req = cls()
240
311
  assert req.check_cmd == ["test", "-x", dns_plugin_path]
241
312
 
@@ -281,22 +352,25 @@ class TestCheckRequirements:
281
352
 
282
353
  async def test_check_requirements_returns_false_on_overlay_failure(self):
283
354
  with (
355
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
284
356
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
285
357
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
358
+ patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
359
+ patch("ceph_devstack.requirements.KernelVersionForOverlay") as MockKernel,
360
+ patch("ceph_devstack.requirements.CgroupV2") as MockCgroup,
286
361
  ):
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
-
362
+ MockLocalHost.os_type = MagicMock(return_value="centos")
363
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
364
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
365
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
366
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
367
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
295
368
  result = await requirements.check_requirements()
296
369
  assert result is False
297
370
 
298
371
  async def test_check_requirements_returns_true_when_all_pass(self):
299
372
  with (
373
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
300
374
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
301
375
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
302
376
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -309,45 +383,24 @@ class TestCheckRequirements:
309
383
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
310
384
  patch("ceph_devstack.requirements.SysctlValue") as MockSysctl,
311
385
  ):
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
-
386
+ MockLocalHost.os_type = MagicMock(return_value="centos")
387
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
388
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
389
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
390
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
391
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
392
+ MockKernelCgroup.return_value = AsyncMock(
393
+ evaluate=AsyncMock(return_value=True)
394
+ )
395
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
340
396
  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
-
397
+ MockSysctl.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
346
398
  result = await requirements.check_requirements()
347
399
  assert result is True
348
400
 
349
401
  async def test_check_requirements_returns_false_on_runtime_failure(self):
350
402
  with (
403
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
351
404
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
352
405
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
353
406
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -359,43 +412,26 @@ class TestCheckRequirements:
359
412
  patch("ceph_devstack.requirements.PodmanRuntime") as MockRuntime,
360
413
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
361
414
  ):
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
-
415
+ MockLocalHost.os_type = MagicMock(return_value="centos")
416
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
417
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
418
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
419
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
420
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
382
421
  mock_kernel_cgroup = AsyncMock()
383
422
  mock_kernel_cgroup.evaluate = AsyncMock(return_value=True)
384
423
  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
-
424
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
390
425
  mock_selinux.return_value = False
391
-
392
426
  result = await requirements.check_requirements()
393
427
  assert result is False
394
428
 
395
429
  async def test_check_requirements_returns_false_on_selinux_bool_failure(self):
396
430
  with (
431
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
397
432
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
398
433
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
434
+ patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
399
435
  patch("ceph_devstack.requirements.KernelVersionForOverlay") as MockKernel,
400
436
  patch("ceph_devstack.requirements.CgroupV2") as MockCgroup,
401
437
  patch(
@@ -405,46 +441,26 @@ class TestCheckRequirements:
405
441
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
406
442
  patch("ceph_devstack.requirements.SELinuxBoolean") as MockSELinuxBoolean,
407
443
  ):
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
444
+ MockLocalHost.os_type = MagicMock(return_value="centos")
445
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
446
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
447
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
448
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
449
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
450
+ MockKernelCgroup.return_value = AsyncMock(
451
+ evaluate=AsyncMock(return_value=True)
452
+ )
453
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
454
+ mock_selinux.return_value = True
455
+ MockSELinuxBoolean.return_value = AsyncMock(
456
+ evaluate=AsyncMock(return_value=False)
457
+ )
458
+ result = await requirements.check_requirements()
459
+ assert result is False
445
460
 
446
461
  async def test_check_requirements_returns_false_on_sysctl_failure(self):
447
462
  with (
463
+ patch("ceph_devstack.requirements.local_host") as MockLocalHost,
448
464
  patch("ceph_devstack.requirements.PodmanPlatform") as MockPlatform,
449
465
  patch("ceph_devstack.requirements.PodmanGraphDriver") as MockGraph,
450
466
  patch("ceph_devstack.requirements.PodmanVersion") as MockVersion,
@@ -457,39 +473,17 @@ class TestCheckRequirements:
457
473
  patch("ceph_devstack.requirements.host.selinux_enforcing") as mock_selinux,
458
474
  patch("ceph_devstack.requirements.SysctlValue") as MockSysctl,
459
475
  ):
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
-
476
+ MockLocalHost.os_type = MagicMock(return_value="centos")
477
+ MockPlatform.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
478
+ MockGraph.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
479
+ MockVersion.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
480
+ MockKernel.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
481
+ MockCgroup.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
482
+ MockKernelCgroup.return_value = AsyncMock(
483
+ evaluate=AsyncMock(return_value=True)
484
+ )
485
+ MockRuntime.return_value = AsyncMock(evaluate=AsyncMock(return_value=True))
488
486
  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
-
487
+ MockSysctl.return_value = AsyncMock(evaluate=AsyncMock(return_value=False))
494
488
  result = await requirements.check_requirements()
495
489
  assert result is False