Skip to content

Commit 032b5e2

Browse files
Skip none overrides on localdns profile (#9188)
1 parent dfd42d4 commit 032b5e2

File tree

4 files changed

+195
-14
lines changed

4 files changed

+195
-14
lines changed

src/aks-preview/HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
* Fix `--localdns-config` parameter to handle null values in JSON configuration files gracefully, preventing crashes when DNS override sections are null.
1415

1516
18.0.0b40
1617
+++++++

src/aks-preview/azext_aks_preview/_helpers.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,19 @@ def get_extension_in_allow_list(result):
448448
if _check_if_extension_type_is_in_allow_list(result.extension_type.lower()):
449449
return result
450450
return None
451+
452+
453+
def process_dns_overrides(overrides_dict, target_dict, build_override_func):
454+
"""Helper function to safely process DNS overrides with null checks.
455+
456+
Processes DNS override dictionaries from LocalDNS configuration,
457+
filtering out null values and applying the build function to valid entries.
458+
459+
:param overrides_dict: Dictionary containing DNS overrides (can be None)
460+
:param target_dict: Target dictionary to populate with processed overrides
461+
:param build_override_func: Function to build override objects from dict values
462+
"""
463+
if overrides_dict is not None:
464+
for key, value in overrides_dict.items():
465+
if value is not None:
466+
target_dict[key] = build_override_func(value)

src/aks-preview/azext_aks_preview/agentpool_decorator.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from azext_aks_preview._helpers import (
5151
get_nodepool_snapshot_by_snapshot_id,
5252
filter_hard_taints,
53+
process_dns_overrides,
5354
)
5455

5556
logger = get_logger(__name__)
@@ -1477,13 +1478,16 @@ def build_override(override_dict):
14771478
return self.models.LocalDNSOverride(**filtered)
14781479

14791480
# Build kubeDNSOverrides and vnetDNSOverrides from the localdns_profile
1480-
kube_overrides = localdns_profile.get("kubeDNSOverrides")
1481-
for key, value in kube_overrides.items():
1482-
kube_dns_overrides[key] = build_override(value)
1483-
1484-
vnet_overrides = localdns_profile.get("vnetDNSOverrides")
1485-
for key, value in vnet_overrides.items():
1486-
vnet_dns_overrides[key] = build_override(value)
1481+
process_dns_overrides(
1482+
localdns_profile.get("kubeDNSOverrides"),
1483+
kube_dns_overrides,
1484+
build_override
1485+
)
1486+
process_dns_overrides(
1487+
localdns_profile.get("vnetDNSOverrides"),
1488+
vnet_dns_overrides,
1489+
build_override
1490+
)
14871491

14881492
agentpool.local_dns_profile = self.models.LocalDNSProfile(
14891493
mode=localdns_profile.get("mode"),
@@ -1816,13 +1820,16 @@ def build_override(override_dict):
18161820
return self.models.LocalDNSOverride(**filtered)
18171821

18181822
# Build kubeDNSOverrides and vnetDNSOverrides from the localdns_profile
1819-
kube_overrides = localdns_profile.get("kubeDNSOverrides")
1820-
for key, value in kube_overrides.items():
1821-
kube_dns_overrides[key] = build_override(value)
1822-
1823-
vnet_overrides = localdns_profile.get("vnetDNSOverrides")
1824-
for key, value in vnet_overrides.items():
1825-
vnet_dns_overrides[key] = build_override(value)
1823+
process_dns_overrides(
1824+
localdns_profile.get("kubeDNSOverrides"),
1825+
kube_dns_overrides,
1826+
build_override
1827+
)
1828+
process_dns_overrides(
1829+
localdns_profile.get("vnetDNSOverrides"),
1830+
vnet_dns_overrides,
1831+
build_override
1832+
)
18261833

18271834
agentpool.local_dns_profile = self.models.LocalDNSProfile(
18281835
mode=localdns_profile.get("mode"),

src/aks-preview/azext_aks_preview/tests/latest/test_agentpool_decorator.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,6 +2684,151 @@ def common_update_blue_green_upgrade_settings(self):
26842684
)
26852685
self.assertEqual(dec_agentpool_3, ground_truth_agentpool_3)
26862686

2687+
def common_update_localdns_profile(self):
2688+
import tempfile
2689+
import json
2690+
import os
2691+
2692+
# Test case 1: LocalDNS config provided - verify method is called
2693+
localdns_config = {
2694+
"mode": "Required",
2695+
"kubeDNSOverrides": {
2696+
".": {
2697+
"cacheDurationInSeconds": 3600,
2698+
"protocol": "PreferUDP"
2699+
}
2700+
}
2701+
}
2702+
2703+
with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json") as f:
2704+
json.dump(localdns_config, f)
2705+
f.flush()
2706+
config_file_path = f.name
2707+
2708+
try:
2709+
dec_1 = AKSPreviewAgentPoolUpdateDecorator(
2710+
self.cmd,
2711+
self.client,
2712+
{"localdns_config": config_file_path},
2713+
self.resource_type,
2714+
self.agentpool_decorator_mode,
2715+
)
2716+
2717+
agentpool_1 = self.create_initialized_agentpool_instance()
2718+
dec_1.context.attach_agentpool(agentpool_1)
2719+
dec_agentpool_1 = dec_1.update_localdns_profile(agentpool_1)
2720+
2721+
# Verify that LocalDNS profile was created and assigned
2722+
self.assertIsNotNone(dec_agentpool_1.local_dns_profile)
2723+
self.assertEqual(dec_agentpool_1.local_dns_profile.mode, "Required")
2724+
2725+
finally:
2726+
os.unlink(config_file_path)
2727+
2728+
# Test case 2: No LocalDNS config provided - no change
2729+
dec_2 = AKSPreviewAgentPoolUpdateDecorator(
2730+
self.cmd,
2731+
self.client,
2732+
{},
2733+
self.resource_type,
2734+
self.agentpool_decorator_mode,
2735+
)
2736+
2737+
agentpool_2 = self.create_initialized_agentpool_instance()
2738+
original_local_dns_profile = agentpool_2.local_dns_profile
2739+
dec_2.context.attach_agentpool(agentpool_2)
2740+
dec_agentpool_2 = dec_2.update_localdns_profile(agentpool_2)
2741+
2742+
# Verify LocalDNS profile wasn't changed
2743+
self.assertEqual(dec_agentpool_2.local_dns_profile, original_local_dns_profile)
2744+
2745+
# Test case 3: LocalDNS config with null values
2746+
localdns_config_with_nulls = {
2747+
"mode": "Required",
2748+
"kubeDNSOverrides": None,
2749+
"vnetDNSOverrides": {
2750+
".": {
2751+
"cacheDurationInSeconds": 1800,
2752+
"protocol": "ForceTCP"
2753+
}
2754+
}
2755+
}
2756+
2757+
with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json") as f:
2758+
json.dump(localdns_config_with_nulls, f)
2759+
f.flush()
2760+
config_file_path = f.name
2761+
2762+
try:
2763+
dec_3 = AKSPreviewAgentPoolUpdateDecorator(
2764+
self.cmd,
2765+
self.client,
2766+
{"localdns_config": config_file_path},
2767+
self.resource_type,
2768+
self.agentpool_decorator_mode,
2769+
)
2770+
2771+
agentpool_3 = self.create_initialized_agentpool_instance()
2772+
dec_3.context.attach_agentpool(agentpool_3)
2773+
dec_agentpool_3 = dec_3.update_localdns_profile(agentpool_3)
2774+
2775+
# Verify that LocalDNS profile was created with null handling
2776+
self.assertIsNotNone(dec_agentpool_3.local_dns_profile)
2777+
self.assertEqual(dec_agentpool_3.local_dns_profile.mode, "Required")
2778+
# kubeDNSOverrides should be empty dict due to null input
2779+
self.assertEqual(len(dec_agentpool_3.local_dns_profile.kube_dns_overrides), 0)
2780+
# vnetDNSOverrides should have one entry
2781+
self.assertEqual(len(dec_agentpool_3.local_dns_profile.vnet_dns_overrides), 1)
2782+
2783+
finally:
2784+
os.unlink(config_file_path)
2785+
2786+
def common_test_process_dns_overrides_helper(self):
2787+
from azext_aks_preview._helpers import process_dns_overrides
2788+
2789+
# Test the process_dns_overrides utility function functionality
2790+
2791+
# Test case 1: Valid DNS overrides without nulls
2792+
dns_overrides = {
2793+
".": {
2794+
"cacheDurationInSeconds": 3600,
2795+
"protocol": "PreferUDP"
2796+
}
2797+
}
2798+
target_dict = {}
2799+
2800+
def mock_build_override(override_dict):
2801+
return self.models.LocalDNSOverride(
2802+
cache_duration_in_seconds=override_dict.get("cacheDurationInSeconds"),
2803+
protocol=override_dict.get("protocol")
2804+
)
2805+
2806+
process_dns_overrides(dns_overrides, target_dict, mock_build_override)
2807+
self.assertEqual(len(target_dict), 1)
2808+
self.assertIn(".", target_dict)
2809+
2810+
# Test case 2: DNS overrides with null values (should handle gracefully)
2811+
dns_overrides_with_nulls = {
2812+
".": {
2813+
"cacheDurationInSeconds": 1800,
2814+
"protocol": None
2815+
}
2816+
}
2817+
target_dict_2 = {}
2818+
2819+
process_dns_overrides(dns_overrides_with_nulls, target_dict_2, mock_build_override)
2820+
self.assertEqual(len(target_dict_2), 1)
2821+
2822+
# Test case 3: None input (should handle gracefully)
2823+
target_dict_3 = {}
2824+
process_dns_overrides(None, target_dict_3, mock_build_override)
2825+
self.assertEqual(len(target_dict_3), 0)
2826+
2827+
# Test case 4: Empty input (should handle gracefully)
2828+
target_dict_4 = {}
2829+
process_dns_overrides({}, target_dict_4, mock_build_override)
2830+
self.assertEqual(len(target_dict_4), 0)
2831+
26872832

26882833
class AKSPreviewAgentPoolUpdateDecoratorStandaloneModeTestCase(
26892834
AKSPreviewAgentPoolUpdateDecoratorCommonTestCase
@@ -2721,6 +2866,12 @@ def test_update_upgrade_strategy(self):
27212866
def test_update_blue_green_upgrade_settings(self):
27222867
self.common_update_blue_green_upgrade_settings()
27232868

2869+
def test_update_localdns_profile(self):
2870+
self.common_update_localdns_profile()
2871+
2872+
def test_process_dns_overrides_helper(self):
2873+
self.common_test_process_dns_overrides_helper()
2874+
27242875
def test_update_agentpool_profile_preview(self):
27252876
import inspect
27262877

@@ -2808,6 +2959,12 @@ def test_update_upgrade_strategy(self):
28082959
def test_update_blue_green_upgrade_settings(self):
28092960
self.common_update_blue_green_upgrade_settings()
28102961

2962+
def test_update_localdns_profile(self):
2963+
self.common_update_localdns_profile()
2964+
2965+
def test_process_dns_overrides_helper(self):
2966+
self.common_test_process_dns_overrides_helper()
2967+
28112968
def test_update_agentpool_profile_preview(self):
28122969
import inspect
28132970

0 commit comments

Comments
 (0)