fc6e82
From bec5fb60ffae3d1137c7261e5571c2751c5dda25 Mon Sep 17 00:00:00 2001
fc6e82
From: James Falcon <TheRealFalcon@users.noreply.github.com>
fc6e82
Date: Mon, 8 Mar 2021 14:09:47 -0600
fc6e82
Subject: Fix requiring device-number on EC2 derivatives (#836)
fc6e82
fc6e82
#342 (70dbccbb) introduced the ability to determine route-metrics based on
fc6e82
the `device-number` provided by the EC2 IMDS. Not all datasources that
fc6e82
subclass EC2 will have this attribute, so allow the old behavior if
fc6e82
`device-number` is not present.
fc6e82
fc6e82
LP: #1917875
fc6e82
---
fc6e82
 cloudinit/sources/DataSourceEc2.py            |  3 +-
fc6e82
 .../unittests/test_datasource/test_aliyun.py  | 30 +++++++++++++++++++
fc6e82
 2 files changed, 32 insertions(+), 1 deletion(-)
fc6e82
fc6e82
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
fc6e82
index 1930a509..a2105dc7 100644
fc6e82
--- a/cloudinit/sources/DataSourceEc2.py
fc6e82
+++ b/cloudinit/sources/DataSourceEc2.py
fc6e82
@@ -765,13 +765,14 @@ def convert_ec2_metadata_network_config(
fc6e82
         netcfg['ethernets'][nic_name] = dev_config
fc6e82
         return netcfg
fc6e82
     # Apply network config for all nics and any secondary IPv4/v6 addresses
fc6e82
+    nic_idx = 0
fc6e82
     for mac, nic_name in sorted(macs_to_nics.items()):
fc6e82
         nic_metadata = macs_metadata.get(mac)
fc6e82
         if not nic_metadata:
fc6e82
             continue  # Not a physical nic represented in metadata
fc6e82
         # device-number is zero-indexed, we want it 1-indexed for the
fc6e82
         # multiplication on the following line
fc6e82
-        nic_idx = int(nic_metadata['device-number']) + 1
fc6e82
+        nic_idx = int(nic_metadata.get('device-number', nic_idx)) + 1
fc6e82
         dhcp_override = {'route-metric': nic_idx * 100}
fc6e82
         dev_config = {'dhcp4': True, 'dhcp4-overrides': dhcp_override,
fc6e82
                       'dhcp6': False,
fc6e82
diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py
fc6e82
index eb2828d5..cab1ac2b 100644
fc6e82
--- a/tests/unittests/test_datasource/test_aliyun.py
fc6e82
+++ b/tests/unittests/test_datasource/test_aliyun.py
fc6e82
@@ -7,6 +7,7 @@ from unittest import mock
fc6e82
 
fc6e82
 from cloudinit import helpers
fc6e82
 from cloudinit.sources import DataSourceAliYun as ay
fc6e82
+from cloudinit.sources.DataSourceEc2 import convert_ec2_metadata_network_config
fc6e82
 from cloudinit.tests import helpers as test_helpers
fc6e82
 
fc6e82
 DEFAULT_METADATA = {
fc6e82
@@ -183,6 +184,35 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
fc6e82
         self.assertEqual(ay.parse_public_keys(public_keys),
fc6e82
                          public_keys['key-pair-0']['openssh-key'])
fc6e82
 
fc6e82
+    def test_route_metric_calculated_without_device_number(self):
fc6e82
+        """Test that route-metric code works without `device-number`
fc6e82
+
fc6e82
+        `device-number` is part of EC2 metadata, but not supported on aliyun.
fc6e82
+        Attempting to access it will raise a KeyError.
fc6e82
+
fc6e82
+        LP: #1917875
fc6e82
+        """
fc6e82
+        netcfg = convert_ec2_metadata_network_config(
fc6e82
+            {"interfaces": {"macs": {
fc6e82
+                "06:17:04:d7:26:09": {
fc6e82
+                    "interface-id": "eni-e44ef49e",
fc6e82
+                },
fc6e82
+                "06:17:04:d7:26:08": {
fc6e82
+                    "interface-id": "eni-e44ef49f",
fc6e82
+                }
fc6e82
+            }}},
fc6e82
+            macs_to_nics={
fc6e82
+                '06:17:04:d7:26:09': 'eth0',
fc6e82
+                '06:17:04:d7:26:08': 'eth1',
fc6e82
+            }
fc6e82
+        )
fc6e82
+
fc6e82
+        met0 = netcfg['ethernets']['eth0']['dhcp4-overrides']['route-metric']
fc6e82
+        met1 = netcfg['ethernets']['eth1']['dhcp4-overrides']['route-metric']
fc6e82
+
fc6e82
+        # route-metric numbers should be 100 apart
fc6e82
+        assert 100 == abs(met0 - met1)
fc6e82
+
fc6e82
 
fc6e82
 class TestIsAliYun(test_helpers.CiTestCase):
fc6e82
     ALIYUN_PRODUCT = 'Alibaba Cloud ECS'
fc6e82
-- 
fc6e82
2.27.0
fc6e82