Merge ~ack/maas:1940977-lxd-check-required-extensions into maas:master

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 50b5cf702b8cfd6e66a70e7adc4b7f896d91c4b3
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:1940977-lxd-check-required-extensions
Merge into: maas:master
Diff against target: 226 lines (+41/-71)
2 files modified
src/provisioningserver/drivers/pod/lxd.py (+18/-9)
src/provisioningserver/drivers/pod/tests/test_lxd.py (+23/-62)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Adam Collard (community) Approve
Review via email: mp+407661@code.launchpad.net

Commit message

LP:1940977 check for all required LXD extensions

This also adds check for the custom_block_volumes one, which is needed to
compose VMs with multiple disks.

To post a comment you must log in.
Revision history for this message
Adam Collard (adam-collard) :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1940977-lxd-check-required-extensions lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 50b5cf702b8cfd6e66a70e7adc4b7f896d91c4b3

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

LANDING
-b 1940977-lxd-check-required-extensions lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED BUILD
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/10761/consoleText

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/provisioningserver/drivers/pod/lxd.py b/src/provisioningserver/drivers/pod/lxd.py
2index 2c95ca3..48974cd 100644
3--- a/src/provisioningserver/drivers/pod/lxd.py
4+++ b/src/provisioningserver/drivers/pod/lxd.py
5@@ -78,6 +78,12 @@ LXD_BYTE_SUFFIXES = {
6 "EiB": 1024 ** 6,
7 }
8
9+LXD_REQUIRED_EXTENSIONS = frozenset(
10+ ("projects", "virtual-machines", "custom_block_volumes")
11+)
12+
13+LXD_MIN_VERSION = "4.16"
14+
15
16 def convert_lxd_byte_suffixes(value, divisor=None):
17 """Takes the value and converts to a proper integer
18@@ -250,10 +256,7 @@ class LXDPodDriver(PodDriver):
19 def discover_projects(self, pod_id: int, context: dict):
20 """Discover the list of projects in a pod."""
21 with self._get_client(pod_id, context) as client:
22- if not client.has_api_extension("projects"):
23- raise LXDPodError(
24- "Please upgrade your LXD host to 3.6+ for projects support."
25- )
26+ self._check_required_extensions(client)
27 return [
28 {"name": project.name, "description": project.description}
29 for project in client.projects.all()
30@@ -267,11 +270,7 @@ class LXDPodDriver(PodDriver):
31 return self._discover(client, pod_id, context)
32
33 def _discover(self, client: Client, pod_id: int, context: dict):
34- if not client.has_api_extension("virtual-machines"):
35- raise LXDPodError(
36- "Please upgrade your LXD host to 3.19+ for virtual machine support."
37- )
38-
39+ self._check_required_extensions(client)
40 self._ensure_project(client)
41
42 # get MACs for host interfaces. "unknown" interfaces are considered too
43@@ -420,6 +419,16 @@ class LXDPodDriver(PodDriver):
44 # Hints are updated on the region for LXDPodDriver.
45 return DiscoveredPodHints()
46
47+ def _check_required_extensions(self, client):
48+ """Raise an error if the LXD server doesn't support all required features."""
49+ all_extensions = set(client.host_info["api_extensions"])
50+ missing_extensions = sorted(LXD_REQUIRED_EXTENSIONS - all_extensions)
51+ if missing_extensions:
52+ raise LXDPodError(
53+ f"Please upgrade your LXD host to {LXD_MIN_VERSION} or higher "
54+ f"to support the following extensions: {','.join(missing_extensions)}"
55+ )
56+
57 def _get_machine_disks(
58 self, requested_disks, storage_pools, default_storage_pool
59 ):
60diff --git a/src/provisioningserver/drivers/pod/tests/test_lxd.py b/src/provisioningserver/drivers/pod/tests/test_lxd.py
61index 7dc9638..6e49020 100644
62--- a/src/provisioningserver/drivers/pod/tests/test_lxd.py
63+++ b/src/provisioningserver/drivers/pod/tests/test_lxd.py
64@@ -106,7 +106,15 @@ class TestLXDPodDriver(MAASTestCase):
65
66 def make_client(trusted):
67 client = MagicMock(trusted=trusted)
68- client.has_api_extension.return_value = True
69+ client.host_info = {
70+ "api_extensions": sorted(lxd_module.LXD_REQUIRED_EXTENSIONS),
71+ "environment": {
72+ "architectures": ["x86_64", "i686"],
73+ "kernel_architecture": "x86_64",
74+ "server_name": "lxd-server",
75+ "server_version": "4.1",
76+ },
77+ }
78 if fail_trusting:
79 mock_response = Mock(status_code=403)
80 mock_response.json.return_value = {"error": "auth failed"}
81@@ -435,32 +443,23 @@ class TestLXDPodDriver(MAASTestCase):
82 yield driver.power_query(pod_id, context)
83
84 @inlineCallbacks
85- def test_discover_requires_client_to_have_vm_support(self):
86+ def test_discover_checks_required_extensions(self):
87 context = self.make_parameters_context()
88 driver = lxd_module.LXDPodDriver()
89 _, client = self.mock_client()
90- client.has_api_extension.return_value = False
91- error_msg = "Please upgrade your LXD host to *."
92+ client.host_info["api_extensions"].remove("projects")
93+ error_msg = (
94+ "Please upgrade your LXD host to 4.16 or higher "
95+ "to support the following extensions: projects"
96+ )
97 with ExpectedException(lxd_module.LXDPodError, error_msg):
98 yield driver.discover(None, context)
99- self.assertThat(
100- client.has_api_extension, MockCalledOnceWith("virtual-machines")
101- )
102
103 @inlineCallbacks
104 def test_discover(self):
105 context = self.make_parameters_context()
106 driver = lxd_module.LXDPodDriver()
107 _, client = self.mock_client()
108- name = factory.make_name("hostname")
109- client.host_info = {
110- "environment": {
111- "architectures": ["x86_64", "i686"],
112- "kernel_architecture": "x86_64",
113- "server_name": name,
114- "server_version": "1.2.3",
115- }
116- }
117 mac_address = factory.make_mac_address()
118 lxd_net1 = Mock(type="physical")
119 lxd_net1.state.return_value = Mock(hwaddr=mac_address)
120@@ -470,8 +469,8 @@ class TestLXDPodDriver(MAASTestCase):
121 client.networks.all.return_value = [lxd_net1, lxd_net2]
122 discovered_pod = yield driver.discover(None, context)
123 self.assertItemsEqual(["amd64/generic"], discovered_pod.architectures)
124- self.assertEqual(name, discovered_pod.name)
125- self.assertEqual(discovered_pod.version, "1.2.3")
126+ self.assertEqual("lxd-server", discovered_pod.name)
127+ self.assertEqual(discovered_pod.version, "4.1")
128 self.assertItemsEqual([mac_address], discovered_pod.mac_addresses)
129 self.assertEqual(-1, discovered_pod.cores)
130 self.assertEqual(-1, discovered_pod.cpu_speed)
131@@ -498,15 +497,6 @@ class TestLXDPodDriver(MAASTestCase):
132 context = self.make_parameters_context()
133 driver = lxd_module.LXDPodDriver()
134 _, client = self.mock_client()
135- name = factory.make_name("hostname")
136- client.host_info = {
137- "environment": {
138- "architectures": ["x86_64", "i686"],
139- "kernel_architecture": "x86_64",
140- "server_name": name,
141- "server_version": "1.2.3",
142- }
143- }
144 mac_address = factory.make_mac_address()
145 lxd_network = Mock(type="unknown")
146 lxd_network.state.return_value = Mock(hwaddr=mac_address)
147@@ -520,14 +510,6 @@ class TestLXDPodDriver(MAASTestCase):
148 project_name = context["project"]
149 _, client = self.mock_client()
150 client.project = project_name
151- client.host_info = {
152- "environment": {
153- "architectures": ["x86_64", "i686"],
154- "kernel_architecture": "x86_64",
155- "server_name": factory.make_name("hostname"),
156- "server_version": "1.2.3",
157- }
158- }
159 client.projects.exists.return_value = True
160 driver = lxd_module.LXDPodDriver()
161 yield driver.discover(None, context)
162@@ -540,15 +522,6 @@ class TestLXDPodDriver(MAASTestCase):
163 project_name = context["project"]
164 _, client = self.mock_client()
165 client.project = project_name
166- client.has_api_extension.return_value = True
167- client.host_info = {
168- "environment": {
169- "architectures": ["x86_64", "i686"],
170- "kernel_architecture": "x86_64",
171- "server_name": factory.make_name("hostname"),
172- "server_version": "1.2.3",
173- }
174- }
175 client.projects.exists.return_value = False
176 driver = lxd_module.LXDPodDriver()
177 yield driver.discover(None, context)
178@@ -564,32 +537,23 @@ class TestLXDPodDriver(MAASTestCase):
179 )
180
181 @inlineCallbacks
182- def test_discover_projects_requires_projects_support(self):
183+ def test_discover_projects_checks_required_extensions(self):
184 context = self.make_parameters_context()
185 driver = lxd_module.LXDPodDriver()
186 _, client = self.mock_client()
187- client.has_api_extension.return_value = False
188- error_msg = "Please upgrade your LXD host to *."
189+ client.host_info["api_extensions"].remove("virtual-machines")
190+ error_msg = (
191+ "Please upgrade your LXD host to 4.16 or higher "
192+ "to support the following extensions: virtual-machines"
193+ )
194 with ExpectedException(lxd_module.LXDPodError, error_msg):
195 yield driver.discover_projects(None, context)
196- self.assertThat(
197- client.has_api_extension, MockCalledOnceWith("projects")
198- )
199
200 @inlineCallbacks
201 def test_discover_projects(self):
202 context = self.make_parameters_context()
203 driver = lxd_module.LXDPodDriver()
204 _, client = self.mock_client()
205- name = factory.make_name("hostname")
206- client.host_info = {
207- "environment": {
208- "architectures": ["x86_64", "i686"],
209- "kernel_architecture": "x86_64",
210- "server_name": name,
211- "server_version": "1.2.3",
212- }
213- }
214 proj1 = Mock()
215 proj1.name = "proj1"
216 proj1.description = "Project 1"
217@@ -1026,9 +990,6 @@ class TestLXDPodDriver(MAASTestCase):
218 client.resources = {
219 factory.make_name("rkey"): factory.make_name("rvalue")
220 }
221- client.host_info = {
222- factory.make_name("hkey"): factory.make_name("hvalue")
223- }
224
225 def mock_iface(name, mac):
226 iface = Mock()

Subscribers

People subscribed via source and target branches