Merge ~ltrager/maas:lp1835275_2.6 into maas:2.6

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: 3e60de3e98265c202e9835b8174fed0d03c20693
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:lp1835275_2.6
Merge into: maas:2.6
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
Lee Trager (community) Approve
Review via email: mp+370389@code.launchpad.net

Commit message

Backport of 302d171 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) wrote :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/metadataserver/tests/test_api.py b/src/metadataserver/tests/test_api.py
index 45a8361..e9f4b25 100644
--- a/src/metadataserver/tests/test_api.py
+++ b/src/metadataserver/tests/test_api.py
@@ -114,7 +114,6 @@ from testtools.matchers import (
114 ContainsAll,114 ContainsAll,
115 ContainsDict,115 ContainsDict,
116 Equals,116 Equals,
117 HasLength,
118 KeysEqual,117 KeysEqual,
119 StartsWith,118 StartsWith,
120)119)
@@ -855,7 +854,7 @@ class TestMetadataCommon(MAASServerTestCase):
855 self.assertThat(content, LooksLikeCloudInit)854 self.assertThat(content, LooksLikeCloudInit)
856 self.assertThat(855 self.assertThat(
857 yaml.safe_load(content['cloud-init']),856 yaml.safe_load(content['cloud-init']),
858 KeysEqual("system_info"))857 KeysEqual("system_info", "runcmd"))
859858
860 def test_vendor_data_node_without_def_user_includes_no_system_info(self):859 def test_vendor_data_node_without_def_user_includes_no_system_info(self):
861 # Test vendor_data includes no system_info when the node has an owner860 # Test vendor_data includes no system_info when the node has an owner
@@ -871,7 +870,7 @@ class TestMetadataCommon(MAASServerTestCase):
871 self.assertThat(content, LooksLikeCloudInit)870 self.assertThat(content, LooksLikeCloudInit)
872 self.assertThat(871 self.assertThat(
873 yaml.safe_load(content['cloud-init']),872 yaml.safe_load(content['cloud-init']),
874 HasLength(0))873 KeysEqual('runcmd'))
875874
876 def test_vendor_data_for_node_without_owner_includes_no_system_info(self):875 def test_vendor_data_for_node_without_owner_includes_no_system_info(self):
877 view_name = self.get_metadata_name('-meta-data')876 view_name = self.get_metadata_name('-meta-data')
@@ -883,7 +882,7 @@ class TestMetadataCommon(MAASServerTestCase):
883 self.assertThat(content, LooksLikeCloudInit)882 self.assertThat(content, LooksLikeCloudInit)
884 self.assertThat(883 self.assertThat(
885 yaml.safe_load(content['cloud-init']),884 yaml.safe_load(content['cloud-init']),
886 HasLength(0))885 KeysEqual('runcmd'))
887886
888 def test_vendor_data_calls_through_to_get_vendor_data(self):887 def test_vendor_data_calls_through_to_get_vendor_data(self):
889 # i.e. for further information, see `get_vendor_data`.888 # i.e. for further information, see `get_vendor_data`.
diff --git a/src/metadataserver/tests/test_vendor_data.py b/src/metadataserver/tests/test_vendor_data.py
index a5db4fc..ad770d2 100644
--- a/src/metadataserver/tests/test_vendor_data.py
+++ b/src/metadataserver/tests/test_vendor_data.py
@@ -5,10 +5,14 @@
55
6__all__ = []6__all__ = []
77
8import random
9
10from maasserver.enum import NODE_STATUS
8from maasserver.models import (11from maasserver.models import (
9 Config,12 Config,
10 NodeMetadata,13 NodeMetadata,
11)14)
15from maasserver.node_status import COMMISSIONING_LIKE_STATUSES
12from maasserver.server_address import get_maas_facing_server_host16from maasserver.server_address import get_maas_facing_server_host
13from maasserver.testing.factory import factory17from maasserver.testing.factory import factory
14from maasserver.testing.fixtures import RBACEnabled18from maasserver.testing.fixtures import RBACEnabled
@@ -237,7 +241,8 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
237 }))241 }))
238242
239 def test_yields_configuration_when_machine_install_kvm_true(self):243 def test_yields_configuration_when_machine_install_kvm_true(self):
240 node = factory.make_Node(osystem='ubuntu', netboot=False)244 node = factory.make_Node(
245 status=NODE_STATUS.DEPLOYING, osystem='ubuntu', netboot=False)
241 node.install_kvm = True246 node.install_kvm = True
242 configuration = get_vendor_data(node, None)247 configuration = get_vendor_data(node, None)
243 config = str(dict(configuration))248 config = str(dict(configuration))
@@ -271,7 +276,8 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
271276
272 def test_includes_smt_off_for_install_kvm_on_ppc64(self):277 def test_includes_smt_off_for_install_kvm_on_ppc64(self):
273 node = factory.make_Node(278 node = factory.make_Node(
274 osystem='ubuntu', netboot=False, architecture='ppc64el/generic')279 status=NODE_STATUS.DEPLOYING, osystem='ubuntu', netboot=False,
280 architecture='ppc64el/generic')
275 node.install_kvm = True281 node.install_kvm = True
276 configuration = get_vendor_data(node, None)282 configuration = get_vendor_data(node, None)
277 config = dict(configuration)283 config = dict(configuration)
@@ -288,6 +294,26 @@ class TestGenerateRackControllerConfiguration(MAASServerTestCase):
288 self.assertThat(config['runcmd'], Contains(['/etc/rc.local']))294 self.assertThat(config['runcmd'], Contains(['/etc/rc.local']))
289295
290296
297class TestGenerateEphemeralNetplanLockRemoval(MAASServerTestCase):
298 """Tests for `generate_ephemeral_netplan_lock_removal`."""
299
300 def test__does_nothing_if_deploying(self):
301 # MAAS transitions a machine from DEPLOYING to DEPLOYED after
302 # user_data has been requested. Make sure deploying nodes don't
303 # get this config.
304 node = factory.make_Node(status=NODE_STATUS.DEPLOYING)
305 configuration = get_vendor_data(node, None)
306 config = dict(configuration)
307 self.assertNotIn('runcmd', config)
308
309 def test__removes_lock_when_ephemeral(self):
310 node = factory.make_Node(
311 status=random.choice(COMMISSIONING_LIKE_STATUSES))
312 configuration = get_vendor_data(node, None)
313 config = dict(configuration)
314 self.assertThat(config['runcmd'], Contains('rm -rf /run/netplan'))
315
316
291class TestGenerateEphemeralDeploymentNetworkConfiguration(MAASServerTestCase):317class TestGenerateEphemeralDeploymentNetworkConfiguration(MAASServerTestCase):
292 """Tests for `generate_ephemeral_deployment_network_configuration`."""318 """Tests for `generate_ephemeral_deployment_network_configuration`."""
293319
@@ -303,8 +329,10 @@ class TestGenerateEphemeralDeploymentNetworkConfiguration(MAASServerTestCase):
303 config = dict(configuration)329 config = dict(configuration)
304 self.assertThat(330 self.assertThat(
305 config['write_files'][0]['path'],331 config['write_files'][0]['path'],
306 Contains("/etc/netplan/config.yaml"))332 Contains("/etc/netplan/50-maas.yaml"))
307 self.assertThat(config['runcmd'], Contains("netplan apply"))333 # Make sure netplan's lock is removed before applying the config
334 self.assertEquals(config['runcmd'][0], 'rm -rf /run/netplan')
335 self.assertEquals(config['runcmd'][1], 'netplan apply --debug')
308336
309337
310class TestGenerateVcenterConfiguration(MAASServerTestCase):338class TestGenerateVcenterConfiguration(MAASServerTestCase):
@@ -312,19 +340,24 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
312340
313 def test_does_nothing_if_not_vmware(self):341 def test_does_nothing_if_not_vmware(self):
314 mock_get_configs = self.patch(Config.objects, 'get_configs')342 mock_get_configs = self.patch(Config.objects, 'get_configs')
315 node = factory.make_Node(owner=factory.make_admin())343 node = factory.make_Node(
344 status=NODE_STATUS.DEPLOYING, owner=factory.make_admin())
316 config = get_vendor_data(node, None)345 config = get_vendor_data(node, None)
317 self.assertThat(mock_get_configs, MockNotCalled())346 self.assertThat(mock_get_configs, MockNotCalled())
318 self.assertDictEqual({}, config)347 self.assertDictEqual({}, config)
319348
320 def test_returns_nothing_if_no_values_set(self):349 def test_returns_nothing_if_no_values_set(self):
321 node = factory.make_Node(osystem='esxi', owner=factory.make_admin())350 node = factory.make_Node(
351 status=NODE_STATUS.DEPLOYING, osystem='esxi',
352 owner=factory.make_admin())
322 node.nodemetadata_set.create(key='vcenter_registration', value='True')353 node.nodemetadata_set.create(key='vcenter_registration', value='True')
323 config = get_vendor_data(node, None)354 config = get_vendor_data(node, None)
324 self.assertDictEqual({}, config)355 self.assertDictEqual({}, config)
325356
326 def test_returns_vcenter_yaml(self):357 def test_returns_vcenter_yaml(self):
327 node = factory.make_Node(osystem='esxi', owner=factory.make_admin())358 node = factory.make_Node(
359 status=NODE_STATUS.DEPLOYING, osystem='esxi',
360 owner=factory.make_admin())
328 node.nodemetadata_set.create(key='vcenter_registration', value='True')361 node.nodemetadata_set.create(key='vcenter_registration', value='True')
329 vcenter = {362 vcenter = {
330 'vcenter_server': factory.make_name('vcenter_server'),363 'vcenter_server': factory.make_name('vcenter_server'),
@@ -343,7 +376,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
343376
344 def test_returns_vcenter_yaml_if_rbac_admin(self):377 def test_returns_vcenter_yaml_if_rbac_admin(self):
345 rbac = self.useFixture(RBACEnabled())378 rbac = self.useFixture(RBACEnabled())
346 node = factory.make_Node(osystem='esxi', owner=factory.make_User())379 node = factory.make_Node(
380 status=NODE_STATUS.DEPLOYING, osystem='esxi',
381 owner=factory.make_User())
347 node.nodemetadata_set.create(key='vcenter_registration', value='True')382 node.nodemetadata_set.create(key='vcenter_registration', value='True')
348 rbac.store.add_pool(node.pool)383 rbac.store.add_pool(node.pool)
349 rbac.store.allow(node.owner.username, node.pool, 'admin-machines')384 rbac.store.allow(node.owner.username, node.pool, 'admin-machines')
@@ -364,7 +399,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
364399
365 def test_returns_nothing_if_rbac_user(self):400 def test_returns_nothing_if_rbac_user(self):
366 rbac = self.useFixture(RBACEnabled())401 rbac = self.useFixture(RBACEnabled())
367 node = factory.make_Node(osystem='esxi', owner=factory.make_User())402 node = factory.make_Node(
403 status=NODE_STATUS.DEPLOYING, osystem='esxi',
404 owner=factory.make_User())
368 node.nodemetadata_set.create(key='vcenter_registration', value='True')405 node.nodemetadata_set.create(key='vcenter_registration', value='True')
369 rbac.store.add_pool(node.pool)406 rbac.store.add_pool(node.pool)
370 rbac.store.allow(node.owner.username, node.pool, 'deploy-machines')407 rbac.store.allow(node.owner.username, node.pool, 'deploy-machines')
@@ -380,7 +417,7 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
380 self.assertDictEqual({}, config)417 self.assertDictEqual({}, config)
381418
382 def test_returns_nothing_if_no_user(self):419 def test_returns_nothing_if_no_user(self):
383 node = factory.make_Node(osystem='esxi')420 node = factory.make_Node(status=NODE_STATUS.DEPLOYING, osystem='esxi')
384 for i in ['server', 'username', 'password', 'datacenter']:421 for i in ['server', 'username', 'password', 'datacenter']:
385 key = 'vcenter_%s' % i422 key = 'vcenter_%s' % i
386 Config.objects.set_config(key, factory.make_name(key))423 Config.objects.set_config(key, factory.make_name(key))
@@ -388,7 +425,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
388 self.assertDictEqual({}, config)425 self.assertDictEqual({}, config)
389426
390 def test_returns_nothing_if_user(self):427 def test_returns_nothing_if_user(self):
391 node = factory.make_Node(osystem='esxi', owner=factory.make_User())428 node = factory.make_Node(
429 status=NODE_STATUS.DEPLOYING, osystem='esxi',
430 owner=factory.make_User())
392 for i in ['server', 'username', 'password', 'datacenter']:431 for i in ['server', 'username', 'password', 'datacenter']:
393 key = 'vcenter_%s' % i432 key = 'vcenter_%s' % i
394 Config.objects.set_config(key, factory.make_name(key))433 Config.objects.set_config(key, factory.make_name(key))
@@ -396,7 +435,9 @@ class TestGenerateVcenterConfiguration(MAASServerTestCase):
396 self.assertDictEqual({}, config)435 self.assertDictEqual({}, config)
397436
398 def test_returns_nothing_if_vcenter_registration_not_set(self):437 def test_returns_nothing_if_vcenter_registration_not_set(self):
399 node = factory.make_Node(osystem='esxi', owner=factory.make_admin())438 node = factory.make_Node(
439 status=NODE_STATUS.DEPLOYING, osystem='esxi',
440 owner=factory.make_admin())
400 for i in ['server', 'username', 'password', 'datacenter']:441 for i in ['server', 'username', 'password', 'datacenter']:
401 key = 'vcenter_%s' % i442 key = 'vcenter_%s' % i
402 Config.objects.set_config(key, factory.make_name(key))443 Config.objects.set_config(key, factory.make_name(key))
diff --git a/src/metadataserver/vendor_data.py b/src/metadataserver/vendor_data.py
index b4c7adf..1e992d9 100644
--- a/src/metadataserver/vendor_data.py
+++ b/src/metadataserver/vendor_data.py
@@ -17,6 +17,7 @@ from maasserver.models import (
17 Config,17 Config,
18 NodeMetadata,18 NodeMetadata,
19)19)
20from maasserver.node_status import COMMISSIONING_LIKE_STATUSES
20from maasserver.permissions import NodePermission21from maasserver.permissions import NodePermission
21from maasserver.preseed import get_network_yaml_settings22from maasserver.preseed import get_network_yaml_settings
22from maasserver.preseed_network import NodeNetworkConfiguration23from maasserver.preseed_network import NodeNetworkConfiguration
@@ -34,6 +35,7 @@ def get_vendor_data(node, proxy):
34 generate_ntp_configuration(node),35 generate_ntp_configuration(node),
35 generate_rack_controller_configuration(node, proxy),36 generate_rack_controller_configuration(node, proxy),
36 generate_kvm_pod_configuration(node),37 generate_kvm_pod_configuration(node),
38 generate_ephemeral_netplan_lock_removal(node),
37 generate_ephemeral_deployment_network_configuration(node),39 generate_ephemeral_deployment_network_configuration(node),
38 generate_vcenter_configuration(node),40 generate_vcenter_configuration(node),
39 ))41 ))
@@ -110,6 +112,20 @@ def generate_rack_controller_configuration(node, proxy):
110 ]112 ]
111113
112114
115def generate_ephemeral_netplan_lock_removal(node):
116 """Remove netplan's interface lock.
117
118 When booting a machine over the network netplan creates a configuration
119 file in /run/netplan for the interface used to boot. This contains the
120 settings used on boot(DHCP), what renderer was used(networkd), and marks
121 the interface as critical. Netplan will ensure interfaces marked critical
122 will always have the specified configuration applied. This overrides
123 anything put in /etc/netplan breaking custom network configuration."""
124
125 if node.status in COMMISSIONING_LIKE_STATUSES:
126 yield 'runcmd', ['rm -rf /run/netplan']
127
128
113def generate_ephemeral_deployment_network_configuration(node):129def generate_ephemeral_deployment_network_configuration(node):
114 """Generate cloud-init network configuration for ephemeral deployment."""130 """Generate cloud-init network configuration for ephemeral deployment."""
115 if node.ephemeral_deployment:131 if node.ephemeral_deployment:
@@ -125,10 +141,13 @@ def generate_ephemeral_deployment_network_configuration(node):
125 yield "write_files", [141 yield "write_files", [
126 {142 {
127 'content': network_config_yaml,143 'content': network_config_yaml,
128 'path': "/etc/netplan/config.yaml",144 'path': "/etc/netplan/50-maas.yaml",
129 }145 }
130 ]146 ]
131 yield "runcmd", ["netplan apply"]147 yield "runcmd", [
148 "rm -rf /run/netplan",
149 "netplan apply --debug",
150 ]
132151
133152
134def generate_kvm_pod_configuration(node):153def generate_kvm_pod_configuration(node):

Subscribers

People subscribed via source and target branches