Merge ~chad.smith/cloud-init:feature/ec2-secondary-nics into cloud-init:master

Proposed by Chad Smith
Status: Work in progress
Proposed branch: ~chad.smith/cloud-init:feature/ec2-secondary-nics
Merge into: cloud-init:master
Diff against target: 463 lines (+210/-75)
3 files modified
cloudinit/sources/DataSourceEc2.py (+47/-15)
doc/rtd/topics/datasources/ec2.rst (+3/-0)
tests/unittests/test_datasource/test_ec2.py (+160/-60)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
cloud-init Commiters Pending
Review via email: mp+369792@code.launchpad.net

Commit message

ec2: render secondary IPs on primary nic when present in metadata

Parse local-ipv4s and subnet-ipv4-cidr-block on EC2 metadata version
2018-09-24 to obtain secondary nic private IPs and network mask for
the primary nic.

In adding this feature, convert DataSourceEc2.network_config to
emit network version 2 instead of version 1.

To allow for retaining original network config behavior on earlier
distribution series, surface a datasource config option
configure_secondary_ips which defaults to True on tip.

Older/stable distribution series will set configure_secondary_ips
default to False.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:a16796ed79fc4d58710fa018571011d1adefc032
https://jenkins.ubuntu.com/server/job/cloud-init-ci/757/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Dan Watkins (oddbloke) wrote :

Overall, this looks good, thanks! I have a few inline comments/questions, but the overall structure/logic seems sound to me.

(Looks like the CI failures are due to linting.)

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

Thanks! A couple of follow-ups, and a couple of nits I missed first time around.

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

PASSED: Continuous integration, rev:f6b0d9eb283917f4c2a5a5f863ad07c048346199
https://jenkins.ubuntu.com/server/job/cloud-init-ci/759/
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/759/rebuild

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

PASSED: Continuous integration, rev:db953566a9e6df91b4eaeebb813e45726136316c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/761/
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/761/rebuild

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

FAILED: Continuous integration, rev:047a654e9b7ca8dd8115aab2467c55f25ba312ca
https://jenkins.ubuntu.com/server/job/cloud-init-ci/762/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:2ae7c7c3b3ee6522f31a4efc6b993e43e82c5bb9
https://jenkins.ubuntu.com/server/job/cloud-init-ci/765/
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/765/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

Waiting on this change of behavior until after 19.2 upstream release

Revision history for this message
Leo Crawford (leo-leocrawford) wrote :

> Waiting on this change of behavior until after 19.2 upstream release

cloud-init 19.2 was released 17 July. Does this unblock this change being applied?

Revision history for this message
Ryan Harper (raharper) wrote :

I think Chad meant after our next SRU[1], which will begin shortly. I'd expect this come in the SRU after the current planned one.

1. https://wiki.ubuntu.com/StableReleaseUpdates

Revision history for this message
Ryan Harper (raharper) wrote :

Inline comment asking for clarification on AWS DHCP lease contents, requirements for routing traffic to IMDS, DNS, and off-box, as with Azure. Let's document what's needed; we may need to add secondary ips with a metric. See

https://github.com/aws/ec2-net-utils/blob/master/ec2net-functions

For AmazonLinux net implementation; I do see some setting of source_ip and route table/metrics in use.

Revision history for this message
Andrea Scarpino (ilpianista) wrote :

Up! Any news here? Which is the blocker here?

Revision history for this message
Dan Watkins (oddbloke) wrote :

Hi Andrea, this branch was migrated over to GitHub (along with the rest of cloud-init's code hosting :) and was proposed here: https://github.com/canonical/cloud-init/pull/114

It landed in March and was included in the 20.2 cloud-init release. It is available in Ubuntu 20.04 (Focal Fossa), and will be backported to all stable Ubuntu releases (i.e. 16.04 and later) in the next couple of weeks.

Thanks for your interest!

Unmerged commits

2ae7c7c... by Chad Smith

ec2: render secondary IPs on primary nic when present in metadata

Parse local-ipv4s and subnet-ipv4-cidr-block on EC2 metadata version
2018-09-24 to obtain secondary nic private IPs and network mask for
the primary nic.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
index 5c017bf..f39b73f 100644
--- a/cloudinit/sources/DataSourceEc2.py
+++ b/cloudinit/sources/DataSourceEc2.py
@@ -54,7 +54,7 @@ class DataSourceEc2(sources.DataSource):
5454
55 # Priority ordered list of additional metadata versions which will be tried55 # Priority ordered list of additional metadata versions which will be tried
56 # for extended metadata content. IPv6 support comes in 2016-09-0256 # for extended metadata content. IPv6 support comes in 2016-09-02
57 extended_metadata_versions = ['2016-09-02']57 extended_metadata_versions = ['2018-09-24', '2016-09-02']
5858
59 # Setup read_url parameters per get_url_params.59 # Setup read_url parameters per get_url_params.
60 url_max_wait = 12060 url_max_wait = 120
@@ -332,8 +332,13 @@ class DataSourceEc2(sources.DataSource):
332 macs_to_nics = {net.get_interface_mac(iface): iface}332 macs_to_nics = {net.get_interface_mac(iface): iface}
333 net_md = self.metadata.get('network')333 net_md = self.metadata.get('network')
334 if isinstance(net_md, dict):334 if isinstance(net_md, dict):
335 # SRU_BLOCKER: xenial, bionic and disco should default
336 # configure_secondary_ips to False to retain original behavior on
337 # those releases.
335 result = convert_ec2_metadata_network_config(338 result = convert_ec2_metadata_network_config(
336 net_md, macs_to_nics=macs_to_nics, fallback_nic=iface)339 net_md, macs_to_nics=macs_to_nics, fallback_nic=iface,
340 config_secondary_ips=util.is_true(
341 self.ds_cfg.get('configure_secondary_ips', True)))
337342
338 # RELEASE_BLOCKER: xenial should drop the below if statement,343 # RELEASE_BLOCKER: xenial should drop the below if statement,
339 # because the issue being addressed doesn't exist pre-netplan.344 # because the issue being addressed doesn't exist pre-netplan.
@@ -373,7 +378,7 @@ class DataSourceEc2(sources.DataSource):
373 if not self.wait_for_metadata_service():378 if not self.wait_for_metadata_service():
374 return {}379 return {}
375 api_version = self.get_metadata_api_version()380 api_version = self.get_metadata_api_version()
376 crawled_metadata = {}381 crawled_metadata = {'_metadata_api_version': api_version}
377 try:382 try:
378 crawled_metadata['user-data'] = ec2.get_instance_userdata(383 crawled_metadata['user-data'] = ec2.get_instance_userdata(
379 api_version, self.metadata_address)384 api_version, self.metadata_address)
@@ -388,7 +393,6 @@ class DataSourceEc2(sources.DataSource):
388 LOG, "Failed reading from metadata address %s",393 LOG, "Failed reading from metadata address %s",
389 self.metadata_address)394 self.metadata_address)
390 return {}395 return {}
391 crawled_metadata['_metadata_api_version'] = api_version
392 return crawled_metadata396 return crawled_metadata
393397
394398
@@ -523,8 +527,9 @@ def _collect_platform_data():
523 return data527 return data
524528
525529
526def convert_ec2_metadata_network_config(network_md, macs_to_nics=None,530def convert_ec2_metadata_network_config(
527 fallback_nic=None):531 network_md, macs_to_nics=None, fallback_nic=None,
532 config_secondary_ips=True):
528 """Convert ec2 metadata to network config version 1 data dict.533 """Convert ec2 metadata to network config version 1 data dict.
529534
530 @param: network_md: 'network' portion of EC2 metadata.535 @param: network_md: 'network' portion of EC2 metadata.
@@ -535,25 +540,52 @@ def convert_ec2_metadata_network_config(network_md, macs_to_nics=None,
535 not provided, get_interfaces_by_mac is called to get it from the OS.540 not provided, get_interfaces_by_mac is called to get it from the OS.
536 @param: fallback_nic: Optionally provide the primary nic interface name.541 @param: fallback_nic: Optionally provide the primary nic interface name.
537 This nic will be guaranteed to minimally have a dhcp4 configuration.542 This nic will be guaranteed to minimally have a dhcp4 configuration.
543 @param: config_secondary_ips: Boolean set True to configure any
544 secondary IPs described by the metadata service.
538545
539 @return A dict of network config version 1 based on the metadata and macs.546 @return A dict of network config version 2 based on the metadata and macs.
540 """547 """
541 netcfg = {'version': 1, 'config': []}548 netcfg = {'version': 2, 'ethernets': {}}
542 if not macs_to_nics:549 if not macs_to_nics:
543 macs_to_nics = net.get_interfaces_by_mac()550 macs_to_nics = net.get_interfaces_by_mac()
544 macs_metadata = network_md['interfaces']['macs']551 macs_metadata = network_md['interfaces']['macs']
545 for mac, nic_name in macs_to_nics.items():552 for mac, nic_name in macs_to_nics.items():
553 dev_config = {}
546 nic_metadata = macs_metadata.get(mac)554 nic_metadata = macs_metadata.get(mac)
547 if not nic_metadata:555 if not nic_metadata:
548 continue # Not a physical nic represented in metadata556 continue # Not a physical nic represented in metadata
549 nic_cfg = {'type': 'physical', 'name': nic_name, 'subnets': []}557 local_ipv4s = nic_metadata.get('local-ipv4s')
550 nic_cfg['mac_address'] = mac558 if not config_secondary_ips:
551 if (nic_name == fallback_nic or nic_metadata.get('public-ipv4s') or559 LOG.debug(
552 nic_metadata.get('local-ipv4s')):560 'Skipping secondary IP config because configure_secondary_ips'
553 nic_cfg['subnets'].append({'type': 'dhcp4'})561 ' datasource config option is False')
562 elif (nic_name == fallback_nic or
563 nic_metadata.get('public-ipv4s') or
564 local_ipv4s):
565 dev_config['dhcp4'] = True
566 # In version < 2018-09-24 local_ipvs is a str with a single IP
567 if isinstance(local_ipv4s, list) and len(local_ipv4s) > 1:
568 dev_config['addresses'] = []
569 subnet_cidr = nic_metadata.get('subnet-ipv4-cidr-block')
570 if not subnet_cidr or len(subnet_cidr.split('/')) != 2:
571 LOG.warning(
572 'Could not parse subnet-ipv4-cidr-block %s.'
573 ' Network config for Secondary IPs default to /32',
574 subnet_cidr)
575 prefix = '32'
576 else:
577 _ip, prefix = subnet_cidr.split('/')
578 # Primary nic IP is at index 0 and obtained via dhcp on Ec2
579 # Iterate over all secondary IPs in local_ipv4s at index >= 1
580 for secondary_ip in local_ipv4s[1:]:
581 dev_config['addresses'].append(
582 '{ip}/{prefix}'.format(ip=secondary_ip, prefix=prefix))
554 if nic_metadata.get('ipv6s'):583 if nic_metadata.get('ipv6s'):
555 nic_cfg['subnets'].append({'type': 'dhcp6'})584 dev_config['dhcp6'] = True
556 netcfg['config'].append(nic_cfg)585 dev_config.update({
586 'match': {'macaddress': mac.lower()},
587 'set-name': nic_name})
588 netcfg['ethernets'][nic_name] = dev_config
557 return netcfg589 return netcfg
558590
559591
diff --git a/doc/rtd/topics/datasources/ec2.rst b/doc/rtd/topics/datasources/ec2.rst
index 76beca9..5535edf 100644
--- a/doc/rtd/topics/datasources/ec2.rst
+++ b/doc/rtd/topics/datasources/ec2.rst
@@ -79,6 +79,9 @@ The settings that may be configured are:
79 * **timeout**: the timeout value provided to urlopen for each individual http79 * **timeout**: the timeout value provided to urlopen for each individual http
80 request. This is used both when selecting a metadata_url and when crawling80 request. This is used both when selecting a metadata_url and when crawling
81 the metadata service. (default: 50)81 the metadata service. (default: 50)
82 * **configure_secondary_ips**: Boolean (default: True) to allow cloud-init
83 to configure any secondary IPs described by the metadata service.
84 On Ubuntu Xenial, Bionic and Disco, this defaults to False.
8285
83An example configuration with the default values is provided below:86An example configuration with the default values is provided below:
8487
diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
index 20d59bf..8ed4c18 100644
--- a/tests/unittests/test_datasource/test_ec2.py
+++ b/tests/unittests/test_datasource/test_ec2.py
@@ -112,6 +112,96 @@ DEFAULT_METADATA = {
112 "services": {"domain": "amazonaws.com", "partition": "aws"},112 "services": {"domain": "amazonaws.com", "partition": "aws"},
113}113}
114114
115# collected from api version 2018-09-24/ with
116# python3 -c 'import json
117# from cloudinit.ec2_utils import get_instance_metadata as gm
118# print(json.dumps(gm("2018-09-24"), indent=1, sort_keys=True))'
119SECONDARY_IP_METADATA_2018_09_24 = {
120 "ami-id": "ami-0986c2ac728528ac2",
121 "ami-launch-index": "0",
122 "ami-manifest-path": "(unknown)",
123 "block-device-mapping": {
124 "ami": "/dev/sda1",
125 "root": "/dev/sda1"
126 },
127 "events": {
128 "maintenance": {
129 "history": "[]",
130 "scheduled": "[]"
131 }
132 },
133 "hostname": "ip-172-31-44-13.us-east-2.compute.internal",
134 "identity-credentials": {
135 "ec2": {
136 "info": {
137 "AccountId": "329910648901",
138 "Code": "Success",
139 "LastUpdated": "2019-07-06T14:22:56Z"
140 }
141 }
142 },
143 "instance-action": "none",
144 "instance-id": "i-069e01e8cc43732f8",
145 "instance-type": "t2.micro",
146 "local-hostname": "ip-172-31-44-13.us-east-2.compute.internal",
147 "local-ipv4": "172.31.44.13",
148 "mac": "0a:07:84:3d:6e:38",
149 "metrics": {
150 "vhostmd": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
151 },
152 "network": {
153 "interfaces": {
154 "macs": {
155 "0a:07:84:3d:6e:38": {
156 "device-number": "0",
157 "interface-id": "eni-0d6335689899ce9cc",
158 "ipv4-associations": {
159 "18.218.219.181": "172.31.44.13"
160 },
161 "local-hostname": ("ip-172-31-44-13.us-east-2."
162 "compute.internal"),
163 "local-ipv4s": [
164 "172.31.44.13",
165 "172.31.45.70"
166 ],
167 "mac": "0a:07:84:3d:6e:38",
168 "owner-id": "329910648901",
169 "public-hostname": ("ec2-18-218-219-181.us-east-2."
170 "compute.amazonaws.com"),
171 "public-ipv4s": "18.218.219.181",
172 "security-group-ids": "sg-0c387755222ba8d2e",
173 "security-groups": "launch-wizard-4",
174 "subnet-id": "subnet-9d7ba0d1",
175 "subnet-ipv4-cidr-block": "172.31.32.0/20",
176 "vpc-id": "vpc-a07f62c8",
177 "vpc-ipv4-cidr-block": "172.31.0.0/16",
178 "vpc-ipv4-cidr-blocks": "172.31.0.0/16"
179 }
180 }
181 }
182 },
183 "placement": {
184 "availability-zone": "us-east-2c"
185 },
186 "profile": "default-hvm",
187 "public-hostname": (
188 "ec2-18-218-219-181.us-east-2.compute.amazonaws.com"),
189 "public-ipv4": "18.218.219.181",
190 "public-keys": {
191 "yourkeyname,e": [
192 "ssh-rsa AAAAW...DZ yourkeyname"
193 ]
194 },
195 "reservation-id": "r-09b4917135cdd33be",
196 "security-groups": "launch-wizard-4",
197 "services": {
198 "domain": "amazonaws.com",
199 "partition": "aws"
200 }
201}
202
203M_PATH_NET = 'cloudinit.sources.DataSourceEc2.net.'
204
115205
116def _register_ssh_keys(rfunc, base_url, keys_data):206def _register_ssh_keys(rfunc, base_url, keys_data):
117 """handle ssh key inconsistencies.207 """handle ssh key inconsistencies.
@@ -261,30 +351,23 @@ class TestEc2(test_helpers.HttprettyTestCase):
261 register_mock_metaserver(instance_id_url, None)351 register_mock_metaserver(instance_id_url, None)
262 return ds352 return ds
263353
264 def test_network_config_property_returns_version_1_network_data(self):354 def test_network_config_property_returns_version_2_network_data(self):
265 """network_config property returns network version 1 for metadata.355 """network_config property returns network version 2 for metadata"""
266
267 Only one device is configured even when multiple exist in metadata.
268 """
269 ds = self._setup_ds(356 ds = self._setup_ds(
270 platform_data=self.valid_platform_data,357 platform_data=self.valid_platform_data,
271 sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},358 sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
272 md={'md': DEFAULT_METADATA})359 md={'md': DEFAULT_METADATA})
273 find_fallback_path = (360 find_fallback_path = M_PATH_NET + 'find_fallback_nic'
274 'cloudinit.sources.DataSourceEc2.net.find_fallback_nic')
275 with mock.patch(find_fallback_path) as m_find_fallback:361 with mock.patch(find_fallback_path) as m_find_fallback:
276 m_find_fallback.return_value = 'eth9'362 m_find_fallback.return_value = 'eth9'
277 ds.get_data()363 ds.get_data()
278364
279 mac1 = '06:17:04:d7:26:09' # Defined in DEFAULT_METADATA365 mac1 = '06:17:04:d7:26:09' # Defined in DEFAULT_METADATA
280 expected = {'version': 1, 'config': [366 expected = {'version': 2, 'ethernets': {'eth9': {
281 {'mac_address': '06:17:04:d7:26:09', 'name': 'eth9',367 'match': {'macaddress': '06:17:04:d7:26:09'}, 'set-name': 'eth9',
282 'subnets': [{'type': 'dhcp4'}, {'type': 'dhcp6'}],368 'dhcp4': True, 'dhcp6': True}}}
283 'type': 'physical'}]}369 patch_path = M_PATH_NET + 'get_interfaces_by_mac'
284 patch_path = (370 get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
285 'cloudinit.sources.DataSourceEc2.net.get_interfaces_by_mac')
286 get_interface_mac_path = (
287 'cloudinit.sources.DataSourceEc2.net.get_interface_mac')
288 with mock.patch(patch_path) as m_get_interfaces_by_mac:371 with mock.patch(patch_path) as m_get_interfaces_by_mac:
289 with mock.patch(find_fallback_path) as m_find_fallback:372 with mock.patch(find_fallback_path) as m_find_fallback:
290 with mock.patch(get_interface_mac_path) as m_get_mac:373 with mock.patch(get_interface_mac_path) as m_get_mac:
@@ -302,21 +385,45 @@ class TestEc2(test_helpers.HttprettyTestCase):
302 platform_data=self.valid_platform_data,385 platform_data=self.valid_platform_data,
303 sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},386 sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
304 md={'md': DEFAULT_METADATA})387 md={'md': DEFAULT_METADATA})
305 find_fallback_path = (388 find_fallback_path = M_PATH_NET + 'find_fallback_nic'
306 'cloudinit.sources.DataSourceEc2.net.find_fallback_nic')
307 with mock.patch(find_fallback_path) as m_find_fallback:389 with mock.patch(find_fallback_path) as m_find_fallback:
308 m_find_fallback.return_value = 'eth9'390 m_find_fallback.return_value = 'eth9'
309 ds.get_data()391 ds.get_data()
310392
311 mac1 = '06:17:04:d7:26:0A' # IPv4 only in DEFAULT_METADATA393 mac1 = '06:17:04:d7:26:0A' # IPv4 only in DEFAULT_METADATA
312 expected = {'version': 1, 'config': [394 expected = {'version': 2, 'ethernets': {'eth9': {
313 {'mac_address': '06:17:04:d7:26:0A', 'name': 'eth9',395 'match': {'macaddress': mac1.lower()}, 'set-name': 'eth9',
314 'subnets': [{'type': 'dhcp4'}],396 'dhcp4': True}}}
315 'type': 'physical'}]}397 patch_path = M_PATH_NET + 'get_interfaces_by_mac'
316 patch_path = (398 get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
317 'cloudinit.sources.DataSourceEc2.net.get_interfaces_by_mac')399 with mock.patch(patch_path) as m_get_interfaces_by_mac:
318 get_interface_mac_path = (400 with mock.patch(find_fallback_path) as m_find_fallback:
319 'cloudinit.sources.DataSourceEc2.net.get_interface_mac')401 with mock.patch(get_interface_mac_path) as m_get_mac:
402 m_get_interfaces_by_mac.return_value = {mac1: 'eth9'}
403 m_find_fallback.return_value = 'eth9'
404 m_get_mac.return_value = mac1
405 self.assertEqual(expected, ds.network_config)
406
407 def test_network_config_property_secondary_private_ips(self):
408 """network_config property configures any secondary ipv4 addresses.
409
410 Only one device is configured even when multiple exist in metadata.
411 """
412 ds = self._setup_ds(
413 platform_data=self.valid_platform_data,
414 sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
415 md={'md': SECONDARY_IP_METADATA_2018_09_24})
416 find_fallback_path = M_PATH_NET + 'find_fallback_nic'
417 with mock.patch(find_fallback_path) as m_find_fallback:
418 m_find_fallback.return_value = 'eth9'
419 ds.get_data()
420
421 mac1 = '0a:07:84:3d:6e:38' # IPv4 with 1 secondary IP
422 expected = {'version': 2, 'ethernets': {'eth9': {
423 'match': {'macaddress': mac1}, 'set-name': 'eth9',
424 'addresses': ['172.31.45.70/20'], 'dhcp4': True}}}
425 patch_path = M_PATH_NET + 'get_interfaces_by_mac'
426 get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
320 with mock.patch(patch_path) as m_get_interfaces_by_mac:427 with mock.patch(patch_path) as m_get_interfaces_by_mac:
321 with mock.patch(find_fallback_path) as m_find_fallback:428 with mock.patch(find_fallback_path) as m_find_fallback:
322 with mock.patch(get_interface_mac_path) as m_get_mac:429 with mock.patch(get_interface_mac_path) as m_get_mac:
@@ -352,8 +459,7 @@ class TestEc2(test_helpers.HttprettyTestCase):
352 register_mock_metaserver(459 register_mock_metaserver(
353 'http://169.254.169.254/2009-04-04/meta-data/', DEFAULT_METADATA)460 'http://169.254.169.254/2009-04-04/meta-data/', DEFAULT_METADATA)
354 mac1 = '06:17:04:d7:26:09' # Defined in DEFAULT_METADATA461 mac1 = '06:17:04:d7:26:09' # Defined in DEFAULT_METADATA
355 get_interface_mac_path = (462 get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
356 'cloudinit.sources.DataSourceEc2.net.get_interface_mac')
357 ds.fallback_nic = 'eth9'463 ds.fallback_nic = 'eth9'
358 with mock.patch(get_interface_mac_path) as m_get_interface_mac:464 with mock.patch(get_interface_mac_path) as m_get_interface_mac:
359 m_get_interface_mac.return_value = mac1465 m_get_interface_mac.return_value = mac1
@@ -362,11 +468,9 @@ class TestEc2(test_helpers.HttprettyTestCase):
362 self.assertIn(468 self.assertIn(
363 'Refreshing stale metadata from prior to upgrade',469 'Refreshing stale metadata from prior to upgrade',
364 self.logs.getvalue())470 self.logs.getvalue())
365 expected = {'version': 1, 'config': [471 expected = {'version': 2, 'ethernets': {'eth9': {
366 {'mac_address': '06:17:04:d7:26:09',472 'match': {'macaddress': mac1}, 'set-name': 'eth9',
367 'name': 'eth9',473 'dhcp4': True, 'dhcp6': True}}}
368 'subnets': [{'type': 'dhcp4'}, {'type': 'dhcp6'}],
369 'type': 'physical'}]}
370 self.assertEqual(expected, ds.network_config)474 self.assertEqual(expected, ds.network_config)
371475
372 def test_ec2_get_instance_id_refreshes_identity_on_upgrade(self):476 def test_ec2_get_instance_id_refreshes_identity_on_upgrade(self):
@@ -546,19 +650,19 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
546650
547 def setUp(self):651 def setUp(self):
548 super(TestConvertEc2MetadataNetworkConfig, self).setUp()652 super(TestConvertEc2MetadataNetworkConfig, self).setUp()
549 self.mac1 = '06:17:04:d7:26:09'653 self.mac1 = '06:17:04:D7:26:09'
550 self.network_metadata = {654 self.network_metadata = {
551 'interfaces': {'macs': {655 'interfaces': {'macs': {
552 self.mac1: {'public-ipv4s': '172.31.2.16'}}}}656 self.mac1: {'mac': self.mac1, 'public-ipv4s': '172.31.2.16'}}}}
553657
554 def test_convert_ec2_metadata_network_config_skips_absent_macs(self):658 def test_convert_ec2_metadata_network_config_skips_absent_macs(self):
555 """Any mac absent from metadata is skipped by network config."""659 """Any mac absent from metadata is skipped by network config."""
556 macs_to_nics = {self.mac1: 'eth9', 'DE:AD:BE:EF:FF:FF': 'vitualnic2'}660 macs_to_nics = {self.mac1: 'eth9', 'DE:AD:BE:EF:FF:FF': 'vitualnic2'}
557661
558 # DE:AD:BE:EF:FF:FF represented by OS but not in metadata662 # DE:AD:BE:EF:FF:FF represented by OS but not in metadata
559 expected = {'version': 1, 'config': [663 expected = {'version': 2, 'ethernets': {'eth9': {
560 {'mac_address': self.mac1, 'type': 'physical',664 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
561 'name': 'eth9', 'subnets': [{'type': 'dhcp4'}]}]}665 'dhcp4': True}}}
562 self.assertEqual(666 self.assertEqual(
563 expected,667 expected,
564 ec2.convert_ec2_metadata_network_config(668 ec2.convert_ec2_metadata_network_config(
@@ -572,9 +676,9 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
572 network_metadata_ipv6['interfaces']['macs'][self.mac1])676 network_metadata_ipv6['interfaces']['macs'][self.mac1])
573 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'677 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
574 nic1_metadata.pop('public-ipv4s')678 nic1_metadata.pop('public-ipv4s')
575 expected = {'version': 1, 'config': [679 expected = {'version': 2, 'ethernets': {'eth9': {
576 {'mac_address': self.mac1, 'type': 'physical',680 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
577 'name': 'eth9', 'subnets': [{'type': 'dhcp6'}]}]}681 'dhcp6': True}}}
578 self.assertEqual(682 self.assertEqual(
579 expected,683 expected,
580 ec2.convert_ec2_metadata_network_config(684 ec2.convert_ec2_metadata_network_config(
@@ -588,9 +692,9 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
588 network_metadata_ipv6['interfaces']['macs'][self.mac1])692 network_metadata_ipv6['interfaces']['macs'][self.mac1])
589 nic1_metadata['local-ipv4s'] = '172.3.3.15'693 nic1_metadata['local-ipv4s'] = '172.3.3.15'
590 nic1_metadata.pop('public-ipv4s')694 nic1_metadata.pop('public-ipv4s')
591 expected = {'version': 1, 'config': [695 expected = {'version': 2, 'ethernets': {'eth9': {
592 {'mac_address': self.mac1, 'type': 'physical',696 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
593 'name': 'eth9', 'subnets': [{'type': 'dhcp4'}]}]}697 'dhcp4': True}}}
594 self.assertEqual(698 self.assertEqual(
595 expected,699 expected,
596 ec2.convert_ec2_metadata_network_config(700 ec2.convert_ec2_metadata_network_config(
@@ -605,9 +709,9 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
605 nic1_metadata['public-ipv4s'] = ''709 nic1_metadata['public-ipv4s'] = ''
606710
607 # When no ipv4 or ipv6 content but fallback_nic set, set dhcp4 config.711 # When no ipv4 or ipv6 content but fallback_nic set, set dhcp4 config.
608 expected = {'version': 1, 'config': [712 expected = {'version': 2, 'ethernets': {'eth9': {
609 {'mac_address': self.mac1, 'type': 'physical',713 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
610 'name': 'eth9', 'subnets': [{'type': 'dhcp4'}]}]}714 'dhcp4': True}}}
611 self.assertEqual(715 self.assertEqual(
612 expected,716 expected,
613 ec2.convert_ec2_metadata_network_config(717 ec2.convert_ec2_metadata_network_config(
@@ -622,10 +726,9 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
622 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'726 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
623 nic1_metadata.pop('public-ipv4s')727 nic1_metadata.pop('public-ipv4s')
624 nic1_metadata['local-ipv4s'] = '10.0.0.42' # Local ipv4 only on vpc728 nic1_metadata['local-ipv4s'] = '10.0.0.42' # Local ipv4 only on vpc
625 expected = {'version': 1, 'config': [729 expected = {'version': 2, 'ethernets': {'eth9': {
626 {'mac_address': self.mac1, 'type': 'physical',730 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
627 'name': 'eth9',731 'dhcp4': True, 'dhcp6': True}}}
628 'subnets': [{'type': 'dhcp4'}, {'type': 'dhcp6'}]}]}
629 self.assertEqual(732 self.assertEqual(
630 expected,733 expected,
631 ec2.convert_ec2_metadata_network_config(734 ec2.convert_ec2_metadata_network_config(
@@ -638,10 +741,9 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
638 nic1_metadata = (741 nic1_metadata = (
639 network_metadata_both['interfaces']['macs'][self.mac1])742 network_metadata_both['interfaces']['macs'][self.mac1])
640 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'743 nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
641 expected = {'version': 1, 'config': [744 expected = {'version': 2, 'ethernets': {'eth9': {
642 {'mac_address': self.mac1, 'type': 'physical',745 'match': {'macaddress': self.mac1.lower()}, 'set-name': 'eth9',
643 'name': 'eth9',746 'dhcp4': True, 'dhcp6': True}}}
644 'subnets': [{'type': 'dhcp4'}, {'type': 'dhcp6'}]}]}
645 self.assertEqual(747 self.assertEqual(
646 expected,748 expected,
647 ec2.convert_ec2_metadata_network_config(749 ec2.convert_ec2_metadata_network_config(
@@ -649,12 +751,10 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
649751
650 def test_convert_ec2_metadata_gets_macs_from_get_interfaces_by_mac(self):752 def test_convert_ec2_metadata_gets_macs_from_get_interfaces_by_mac(self):
651 """Convert Ec2 Metadata calls get_interfaces_by_mac by default."""753 """Convert Ec2 Metadata calls get_interfaces_by_mac by default."""
652 expected = {'version': 1, 'config': [754 expected = {'version': 2, 'ethernets': {'eth9': {
653 {'mac_address': self.mac1, 'type': 'physical',755 'match': {'macaddress': self.mac1.lower()},
654 'name': 'eth9',756 'set-name': 'eth9', 'dhcp4': True}}}
655 'subnets': [{'type': 'dhcp4'}]}]}757 patch_path = M_PATH_NET + 'get_interfaces_by_mac'
656 patch_path = (
657 'cloudinit.sources.DataSourceEc2.net.get_interfaces_by_mac')
658 with mock.patch(patch_path) as m_get_interfaces_by_mac:758 with mock.patch(patch_path) as m_get_interfaces_by_mac:
659 m_get_interfaces_by_mac.return_value = {self.mac1: 'eth9'}759 m_get_interfaces_by_mac.return_value = {self.mac1: 'eth9'}
660 self.assertEqual(760 self.assertEqual(

Subscribers

People subscribed via source and target branches