Merge ~ltrager/maas:remove_netplan_interface_lock into maas:master

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: eb657548b445b1b123f71390e643de7ae769e03c
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:remove_netplan_interface_lock
Merge into: maas:master
Diff against target: 256 lines (+77/-18)
3 files modified
src/metadataserver/tests/test_api.py (+3/-4)
src/metadataserver/tests/test_vendor_data.py (+53/-12)
src/metadataserver/vendor_data.py (+21/-2)
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
Review via email: mp+370289@code.launchpad.net

Commit message

LP: 1835275 - Remove netplan interface lock.

Netplan creates a configuration file which locks the interface used to boot.
This ensures netbooted environments don't get disconnected. MAAS may send
a netplan configuration file which will reconfigure the boot interface. The
script runner will ensure the machine reconnects.

To post a comment you must log in.
Revision history for this message
Lee Trager (ltrager) :
Revision history for this message
Newell Jensen (newell-jensen) wrote :

+1 but don't really see the need to match the naming convention of cloud-init unless there is an actual functional advantage of doing it this way (which was not mentioned in your comment).

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :
eb65754... by Lee Trager

Fix failing tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/metadataserver/tests/test_api.py b/src/metadataserver/tests/test_api.py
2index c6979ff..800f437 100644
3--- a/src/metadataserver/tests/test_api.py
4+++ b/src/metadataserver/tests/test_api.py
5@@ -117,7 +117,6 @@ from testtools.matchers import (
6 ContainsAll,
7 ContainsDict,
8 Equals,
9- HasLength,
10 KeysEqual,
11 StartsWith,
12 )
13@@ -858,7 +857,7 @@ class TestMetadataCommon(MAASServerTestCase):
14 self.assertThat(content, LooksLikeCloudInit)
15 self.assertThat(
16 yaml.safe_load(content['cloud-init']),
17- KeysEqual("system_info"))
18+ KeysEqual("system_info", "runcmd"))
19
20 def test_vendor_data_node_without_def_user_includes_no_system_info(self):
21 # Test vendor_data includes no system_info when the node has an owner
22@@ -874,7 +873,7 @@ class TestMetadataCommon(MAASServerTestCase):
23 self.assertThat(content, LooksLikeCloudInit)
24 self.assertThat(
25 yaml.safe_load(content['cloud-init']),
26- HasLength(0))
27+ KeysEqual('runcmd'))
28
29 def test_vendor_data_for_node_without_owner_includes_no_system_info(self):
30 view_name = self.get_metadata_name('-meta-data')
31@@ -886,7 +885,7 @@ class TestMetadataCommon(MAASServerTestCase):
32 self.assertThat(content, LooksLikeCloudInit)
33 self.assertThat(
34 yaml.safe_load(content['cloud-init']),
35- HasLength(0))
36+ KeysEqual('runcmd'))
37
38 def test_vendor_data_calls_through_to_get_vendor_data(self):
39 # i.e. for further information, see `get_vendor_data`.
40diff --git a/src/metadataserver/tests/test_vendor_data.py b/src/metadataserver/tests/test_vendor_data.py
41index a5db4fc..ad770d2 100644
42--- a/src/metadataserver/tests/test_vendor_data.py
43+++ b/src/metadataserver/tests/test_vendor_data.py
44@@ -5,10 +5,14 @@
45
46 __all__ = []
47
48+import random
49+
50+from maasserver.enum import NODE_STATUS
51 from maasserver.models import (
52 Config,
53 NodeMetadata,
54 )
55+from maasserver.node_status import COMMISSIONING_LIKE_STATUSES
56 from maasserver.server_address import get_maas_facing_server_host
57 from maasserver.testing.factory import factory
58 from maasserver.testing.fixtures import RBACEnabled
59@@ -237,7 +241,8 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
60 }))
61
62 def test_yields_configuration_when_machine_install_kvm_true(self):
63- node = factory.make_Node(osystem='ubuntu', netboot=False)
64+ node = factory.make_Node(
65+ status=NODE_STATUS.DEPLOYING, osystem='ubuntu', netboot=False)
66 node.install_kvm = True
67 configuration = get_vendor_data(node, None)
68 config = str(dict(configuration))
69@@ -271,7 +276,8 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
70
71 def test_includes_smt_off_for_install_kvm_on_ppc64(self):
72 node = factory.make_Node(
73- osystem='ubuntu', netboot=False, architecture='ppc64el/generic')
74+ status=NODE_STATUS.DEPLOYING, osystem='ubuntu', netboot=False,
75+ architecture='ppc64el/generic')
76 node.install_kvm = True
77 configuration = get_vendor_data(node, None)
78 config = dict(configuration)
79@@ -288,6 +294,26 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
80 self.assertThat(config['runcmd'], Contains(['/etc/rc.local']))
81
82
83+class TestGenerateEphemeralNetplanLockRemoval(MAASServerTestCase):
84+ """Tests for `generate_ephemeral_netplan_lock_removal`."""
85+
86+ def test__does_nothing_if_deploying(self):
87+ # MAAS transitions a machine from DEPLOYING to DEPLOYED after
88+ # user_data has been requested. Make sure deploying nodes don't
89+ # get this config.
90+ node = factory.make_Node(status=NODE_STATUS.DEPLOYING)
91+ configuration = get_vendor_data(node, None)
92+ config = dict(configuration)
93+ self.assertNotIn('runcmd', config)
94+
95+ def test__removes_lock_when_ephemeral(self):
96+ node = factory.make_Node(
97+ status=random.choice(COMMISSIONING_LIKE_STATUSES))
98+ configuration = get_vendor_data(node, None)
99+ config = dict(configuration)
100+ self.assertThat(config['runcmd'], Contains('rm -rf /run/netplan'))
101+
102+
103 class TestGenerateEphemeralDeploymentNetworkConfiguration(MAASServerTestCase):
104 """Tests for `generate_ephemeral_deployment_network_configuration`."""
105
106@@ -303,8 +329,10 @@ class TestGenerateEphemeralDeploymentNetworkConfiguration(MAASServerTestCase):
107 config = dict(configuration)
108 self.assertThat(
109 config['write_files'][0]['path'],
110- Contains("/etc/netplan/config.yaml"))
111- self.assertThat(config['runcmd'], Contains("netplan apply"))
112+ Contains("/etc/netplan/50-maas.yaml"))
113+ # Make sure netplan's lock is removed before applying the config
114+ self.assertEquals(config['runcmd'][0], 'rm -rf /run/netplan')
115+ self.assertEquals(config['runcmd'][1], 'netplan apply --debug')
116
117
118 class TestGenerateVcenterConfiguration(MAASServerTestCase):
119@@ -312,19 +340,24 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
120
121 def test_does_nothing_if_not_vmware(self):
122 mock_get_configs = self.patch(Config.objects, 'get_configs')
123- node = factory.make_Node(owner=factory.make_admin())
124+ node = factory.make_Node(
125+ status=NODE_STATUS.DEPLOYING, owner=factory.make_admin())
126 config = get_vendor_data(node, None)
127 self.assertThat(mock_get_configs, MockNotCalled())
128 self.assertDictEqual({}, config)
129
130 def test_returns_nothing_if_no_values_set(self):
131- node = factory.make_Node(osystem='esxi', owner=factory.make_admin())
132+ node = factory.make_Node(
133+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
134+ owner=factory.make_admin())
135 node.nodemetadata_set.create(key='vcenter_registration', value='True')
136 config = get_vendor_data(node, None)
137 self.assertDictEqual({}, config)
138
139 def test_returns_vcenter_yaml(self):
140- node = factory.make_Node(osystem='esxi', owner=factory.make_admin())
141+ node = factory.make_Node(
142+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
143+ owner=factory.make_admin())
144 node.nodemetadata_set.create(key='vcenter_registration', value='True')
145 vcenter = {
146 'vcenter_server': factory.make_name('vcenter_server'),
147@@ -343,7 +376,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
148
149 def test_returns_vcenter_yaml_if_rbac_admin(self):
150 rbac = self.useFixture(RBACEnabled())
151- node = factory.make_Node(osystem='esxi', owner=factory.make_User())
152+ node = factory.make_Node(
153+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
154+ owner=factory.make_User())
155 node.nodemetadata_set.create(key='vcenter_registration', value='True')
156 rbac.store.add_pool(node.pool)
157 rbac.store.allow(node.owner.username, node.pool, 'admin-machines')
158@@ -364,7 +399,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
159
160 def test_returns_nothing_if_rbac_user(self):
161 rbac = self.useFixture(RBACEnabled())
162- node = factory.make_Node(osystem='esxi', owner=factory.make_User())
163+ node = factory.make_Node(
164+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
165+ owner=factory.make_User())
166 node.nodemetadata_set.create(key='vcenter_registration', value='True')
167 rbac.store.add_pool(node.pool)
168 rbac.store.allow(node.owner.username, node.pool, 'deploy-machines')
169@@ -380,7 +417,7 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
170 self.assertDictEqual({}, config)
171
172 def test_returns_nothing_if_no_user(self):
173- node = factory.make_Node(osystem='esxi')
174+ node = factory.make_Node(status=NODE_STATUS.DEPLOYING, osystem='esxi')
175 for i in ['server', 'username', 'password', 'datacenter']:
176 key = 'vcenter_%s' % i
177 Config.objects.set_config(key, factory.make_name(key))
178@@ -388,7 +425,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
179 self.assertDictEqual({}, config)
180
181 def test_returns_nothing_if_user(self):
182- node = factory.make_Node(osystem='esxi', owner=factory.make_User())
183+ node = factory.make_Node(
184+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
185+ owner=factory.make_User())
186 for i in ['server', 'username', 'password', 'datacenter']:
187 key = 'vcenter_%s' % i
188 Config.objects.set_config(key, factory.make_name(key))
189@@ -396,7 +435,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
190 self.assertDictEqual({}, config)
191
192 def test_returns_nothing_if_vcenter_registration_not_set(self):
193- node = factory.make_Node(osystem='esxi', owner=factory.make_admin())
194+ node = factory.make_Node(
195+ status=NODE_STATUS.DEPLOYING, osystem='esxi',
196+ owner=factory.make_admin())
197 for i in ['server', 'username', 'password', 'datacenter']:
198 key = 'vcenter_%s' % i
199 Config.objects.set_config(key, factory.make_name(key))
200diff --git a/src/metadataserver/vendor_data.py b/src/metadataserver/vendor_data.py
201index b4c7adf..1e992d9 100644
202--- a/src/metadataserver/vendor_data.py
203+++ b/src/metadataserver/vendor_data.py
204@@ -17,6 +17,7 @@ from maasserver.models import (
205 Config,
206 NodeMetadata,
207 )
208+from maasserver.node_status import COMMISSIONING_LIKE_STATUSES
209 from maasserver.permissions import NodePermission
210 from maasserver.preseed import get_network_yaml_settings
211 from maasserver.preseed_network import NodeNetworkConfiguration
212@@ -34,6 +35,7 @@ def get_vendor_data(node, proxy):
213 generate_ntp_configuration(node),
214 generate_rack_controller_configuration(node, proxy),
215 generate_kvm_pod_configuration(node),
216+ generate_ephemeral_netplan_lock_removal(node),
217 generate_ephemeral_deployment_network_configuration(node),
218 generate_vcenter_configuration(node),
219 ))
220@@ -110,6 +112,20 @@ def generate_rack_controller_configuration(node, proxy):
221 ]
222
223
224+def generate_ephemeral_netplan_lock_removal(node):
225+ """Remove netplan's interface lock.
226+
227+ When booting a machine over the network netplan creates a configuration
228+ file in /run/netplan for the interface used to boot. This contains the
229+ settings used on boot(DHCP), what renderer was used(networkd), and marks
230+ the interface as critical. Netplan will ensure interfaces marked critical
231+ will always have the specified configuration applied. This overrides
232+ anything put in /etc/netplan breaking custom network configuration."""
233+
234+ if node.status in COMMISSIONING_LIKE_STATUSES:
235+ yield 'runcmd', ['rm -rf /run/netplan']
236+
237+
238 def generate_ephemeral_deployment_network_configuration(node):
239 """Generate cloud-init network configuration for ephemeral deployment."""
240 if node.ephemeral_deployment:
241@@ -125,10 +141,13 @@ def generate_ephemeral_deployment_network_configuration(node):
242 yield "write_files", [
243 {
244 'content': network_config_yaml,
245- 'path': "/etc/netplan/config.yaml",
246+ 'path': "/etc/netplan/50-maas.yaml",
247 }
248 ]
249- yield "runcmd", ["netplan apply"]
250+ yield "runcmd", [
251+ "rm -rf /run/netplan",
252+ "netplan apply --debug",
253+ ]
254
255
256 def generate_kvm_pod_configuration(node):

Subscribers

People subscribed via source and target branches