Merge ~chad.smith/cloud-init:feature/azure-disable-imds-networking into cloud-init:master

Proposed by Chad Smith
Status: Merged
Approved by: Chad Smith
Approved revision: 15a75ea17652fe825cc365aa58f1a85135ec0dfe
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~chad.smith/cloud-init:feature/azure-disable-imds-networking
Merge into: cloud-init:master
Diff against target: 206 lines (+107/-6)
3 files modified
cloudinit/sources/DataSourceAzure.py (+9/-2)
doc/rtd/topics/datasources/azure.rst (+46/-0)
tests/unittests/test_datasource/test_azure.py (+52/-4)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
cloud-init Commiters Pending
Review via email: mp+356989@code.launchpad.net

Commit message

azure: Add apply_network_config option to disable network from IMDS

Azure generates network configuration from the IMDS service and removes
any preexisting hotplug network scripts which exist in Azure cloud images.
Add a datasource configuration option which allows for writing a default
network configuration which sets up dhcp on eth0 and leave the hotplug
handling to the cloud-image scripts.

To disable network-config from Azure IMDS, add the following to
/etc/cloud/cloud.cfg.d/99-azure-no-imds-network.cfg:
datasource:
  Azure:
    apply_network_config: False

LP: #1798424

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

inline comments.

fc655fb... by Chad Smith

add unit test for not removing net scripts when disabled

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:c8efde583fa58b2b1d3f8f5e32d70110bc6df6d8
https://jenkins.ubuntu.com/server/job/cloud-init-ci/400/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/400/rebuild

review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

Minor comment, but it isn't Xenial-only, but rather, Xenial and older; While we've not SRU'd to trusty I think it's worth updating to comment locations to indicate that this is relevant for Ubuntu releases which include ifupdown.

cd9c72f... by Chad Smith

no need to default ds_config back to BUILTIN because we already merge the defaults defined when we intialize ds_cfg

d0d6e4b... by Chad Smith

doc update

Revision history for this message
Chad Smith (chad.smith) :
41a76bc... by Chad Smith

comment update

Revision history for this message
Chad Smith (chad.smith) wrote :

> Minor comment, but it isn't Xenial-only, but rather, Xenial and older; While
> we've not SRU'd to trusty I think it's worth updating to comment locations to
> indicate that this is relevant for Ubuntu releases which include ifupdown.

Thanks Ryan fixed.

928dab8... by Chad Smith

doc update

Revision history for this message
Scott Moser (smoser) :
15a75ea... by Chad Smith

remove comment

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:928dab8e3f7fdea3f7b6e233ee67d9e581c4a71c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/401/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/401/rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:15a75ea17652fe825cc365aa58f1a85135ec0dfe
https://jenkins.ubuntu.com/server/job/cloud-init-ci/402/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/402/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
2index 39391d0..d0358e9 100644
3--- a/cloudinit/sources/DataSourceAzure.py
4+++ b/cloudinit/sources/DataSourceAzure.py
5@@ -207,7 +207,9 @@ BUILTIN_DS_CONFIG = {
6 },
7 'disk_aliases': {'ephemeral0': RESOURCE_DISK_PATH},
8 'dhclient_lease_file': LEASE_FILE,
9+ 'apply_network_config': True, # Use IMDS published network configuration
10 }
11+# RELEASE_BLOCKER: Xenial and earlier apply_network_config default is False
12
13 BUILTIN_CLOUD_CONFIG = {
14 'disk_setup': {
15@@ -458,7 +460,8 @@ class DataSourceAzure(sources.DataSource):
16 except sources.InvalidMetaDataException as e:
17 LOG.warning('Could not crawl Azure metadata: %s', e)
18 return False
19- if self.distro and self.distro.name == 'ubuntu':
20+ if (self.distro and self.distro.name == 'ubuntu' and
21+ self.ds_cfg.get('apply_network_config')):
22 maybe_remove_ubuntu_network_config_scripts()
23
24 # Process crawled data and augment with various config defaults
25@@ -619,7 +622,11 @@ class DataSourceAzure(sources.DataSource):
26 the blacklisted devices.
27 """
28 if not self._network_config:
29- self._network_config = parse_network_config(self._metadata_imds)
30+ if self.ds_cfg.get('apply_network_config'):
31+ nc_src = self._metadata_imds
32+ else:
33+ nc_src = None
34+ self._network_config = parse_network_config(nc_src)
35 return self._network_config
36
37
38diff --git a/doc/rtd/topics/datasources/azure.rst b/doc/rtd/topics/datasources/azure.rst
39index 559011e..f73c369 100644
40--- a/doc/rtd/topics/datasources/azure.rst
41+++ b/doc/rtd/topics/datasources/azure.rst
42@@ -57,6 +57,52 @@ in order to use waagent.conf with cloud-init, the following settings are recomme
43 ResourceDisk.MountPoint=/mnt
44
45
46+Configuration
47+-------------
48+The following configuration can be set for the datasource in system
49+configuration (in `/etc/cloud/cloud.cfg` or `/etc/cloud/cloud.cfg.d/`).
50+
51+The settings that may be configured are:
52+
53+ * **agent_command**: Either __builtin__ (default) or a command to run to getcw
54+ metadata. If __builtin__, get metadata from walinuxagent. Otherwise run the
55+ provided command to obtain metadata.
56+ * **apply_network_config**: Boolean set to True to use network configuration
57+ described by Azure's IMDS endpoint instead of fallback network config of
58+ dhcp on eth0. Default is True. For Ubuntu 16.04 or earlier, default is False.
59+ * **data_dir**: Path used to read metadata files and write crawled data.
60+ * **dhclient_lease_file**: The fallback lease file to source when looking for
61+ custom DHCP option 245 from Azure fabric.
62+ * **disk_aliases**: A dictionary defining which device paths should be
63+ interpreted as ephemeral images. See cc_disk_setup module for more info.
64+ * **hostname_bounce**: A dictionary Azure hostname bounce behavior to react to
65+ metadata changes.
66+ * **hostname_bounce**: A dictionary Azure hostname bounce behavior to react to
67+ metadata changes. Azure will throttle ifup/down in some cases after metadata
68+ has been updated to inform dhcp server about updated hostnames.
69+ * **set_hostname**: Boolean set to True when we want Azure to set the hostname
70+ based on metadata.
71+
72+An example configuration with the default values is provided below:
73+
74+.. sourcecode:: yaml
75+
76+ datasource:
77+ Azure:
78+ agent_command: __builtin__
79+ apply_network_config: true
80+ data_dir: /var/lib/waagent
81+ dhclient_lease_file: /var/lib/dhcp/dhclient.eth0.leases
82+ disk_aliases:
83+ ephemeral0: /dev/disk/cloud/azure_resource
84+ hostname_bounce:
85+ interface: eth0
86+ command: builtin
87+ policy: true
88+ hostname_command: hostname
89+ set_hostname: true
90+
91+
92 Userdata
93 --------
94 Userdata is provided to cloud-init inside the ovf-env.xml file. Cloud-init
95diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
96index 0f4b7bf..cd6e7e7 100644
97--- a/tests/unittests/test_datasource/test_azure.py
98+++ b/tests/unittests/test_datasource/test_azure.py
99@@ -256,7 +256,8 @@ scbus-1 on xpt0 bus 0
100 ])
101 return dsaz
102
103- def _get_ds(self, data, agent_command=None, distro=None):
104+ def _get_ds(self, data, agent_command=None, distro=None,
105+ apply_network=None):
106
107 def dsdevs():
108 return data.get('dsdevs', [])
109@@ -312,6 +313,8 @@ scbus-1 on xpt0 bus 0
110 data.get('sys_cfg', {}), distro=distro, paths=self.paths)
111 if agent_command is not None:
112 dsrc.ds_cfg['agent_command'] = agent_command
113+ if apply_network is not None:
114+ dsrc.ds_cfg['apply_network_config'] = apply_network
115
116 return dsrc
117
118@@ -434,14 +437,26 @@ fdescfs /dev/fd fdescfs rw 0 0
119
120 def test_get_data_on_ubuntu_will_remove_network_scripts(self):
121 """get_data will remove ubuntu net scripts on Ubuntu distro."""
122+ sys_cfg = {'datasource': {'Azure': {'apply_network_config': True}}}
123 odata = {'HostName': "myhost", 'UserName': "myuser"}
124 data = {'ovfcontent': construct_valid_ovf_env(data=odata),
125- 'sys_cfg': {}}
126+ 'sys_cfg': sys_cfg}
127
128 dsrc = self._get_ds(data, distro='ubuntu')
129 dsrc.get_data()
130 self.m_remove_ubuntu_network_scripts.assert_called_once_with()
131
132+ def test_get_data_on_ubuntu_will_not_remove_network_scripts_disabled(self):
133+ """When apply_network_config false, do not remove scripts on Ubuntu."""
134+ sys_cfg = {'datasource': {'Azure': {'apply_network_config': False}}}
135+ odata = {'HostName': "myhost", 'UserName': "myuser"}
136+ data = {'ovfcontent': construct_valid_ovf_env(data=odata),
137+ 'sys_cfg': sys_cfg}
138+
139+ dsrc = self._get_ds(data, distro='ubuntu')
140+ dsrc.get_data()
141+ self.m_remove_ubuntu_network_scripts.assert_not_called()
142+
143 def test_crawl_metadata_returns_structured_data_and_caches_nothing(self):
144 """Return all structured metadata and cache no class attributes."""
145 yaml_cfg = "{agent_command: my_command}\n"
146@@ -523,8 +538,10 @@ fdescfs /dev/fd fdescfs rw 0 0
147
148 def test_network_config_set_from_imds(self):
149 """Datasource.network_config returns IMDS network data."""
150+ sys_cfg = {'datasource': {'Azure': {'apply_network_config': True}}}
151 odata = {}
152- data = {'ovfcontent': construct_valid_ovf_env(data=odata)}
153+ data = {'ovfcontent': construct_valid_ovf_env(data=odata),
154+ 'sys_cfg': sys_cfg}
155 expected_network_config = {
156 'ethernets': {
157 'eth0': {'set-name': 'eth0',
158@@ -803,9 +820,10 @@ fdescfs /dev/fd fdescfs rw 0 0
159 @mock.patch('cloudinit.net.generate_fallback_config')
160 def test_imds_network_config(self, mock_fallback):
161 """Network config is generated from IMDS network data when present."""
162+ sys_cfg = {'datasource': {'Azure': {'apply_network_config': True}}}
163 odata = {'HostName': "myhost", 'UserName': "myuser"}
164 data = {'ovfcontent': construct_valid_ovf_env(data=odata),
165- 'sys_cfg': {}}
166+ 'sys_cfg': sys_cfg}
167
168 dsrc = self._get_ds(data)
169 ret = dsrc.get_data()
170@@ -825,6 +843,36 @@ fdescfs /dev/fd fdescfs rw 0 0
171 @mock.patch('cloudinit.net.get_devicelist')
172 @mock.patch('cloudinit.net.device_driver')
173 @mock.patch('cloudinit.net.generate_fallback_config')
174+ def test_imds_network_ignored_when_apply_network_config_false(
175+ self, mock_fallback, mock_dd, mock_devlist, mock_get_mac):
176+ """When apply_network_config is False, use fallback instead of IMDS."""
177+ sys_cfg = {'datasource': {'Azure': {'apply_network_config': False}}}
178+ odata = {'HostName': "myhost", 'UserName': "myuser"}
179+ data = {'ovfcontent': construct_valid_ovf_env(data=odata),
180+ 'sys_cfg': sys_cfg}
181+ fallback_config = {
182+ 'version': 1,
183+ 'config': [{
184+ 'type': 'physical', 'name': 'eth0',
185+ 'mac_address': '00:11:22:33:44:55',
186+ 'params': {'driver': 'hv_netsvc'},
187+ 'subnets': [{'type': 'dhcp'}],
188+ }]
189+ }
190+ mock_fallback.return_value = fallback_config
191+
192+ mock_devlist.return_value = ['eth0']
193+ mock_dd.return_value = ['hv_netsvc']
194+ mock_get_mac.return_value = '00:11:22:33:44:55'
195+
196+ dsrc = self._get_ds(data)
197+ self.assertTrue(dsrc.get_data())
198+ self.assertEqual(dsrc.network_config, fallback_config)
199+
200+ @mock.patch('cloudinit.net.get_interface_mac')
201+ @mock.patch('cloudinit.net.get_devicelist')
202+ @mock.patch('cloudinit.net.device_driver')
203+ @mock.patch('cloudinit.net.generate_fallback_config')
204 def test_fallback_network_config(self, mock_fallback, mock_dd,
205 mock_devlist, mock_get_mac):
206 """On absent IMDS network data, generate network fallback config."""

Subscribers

People subscribed via source and target branches