Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Pending
* Add blue-green upgrade strategy support for AKS node pools:
- `az aks nodepool add/update/upgrade`: Add `--upgrade-strategy` parameter to switch between rolling and blue-green nodepool upgrades.
- `az aks nodepool add/update/upgrade`: Add `--drain-batch-size`, `--drain-timeout-bg`, `--batch-soak-duration`, `--final-soak-duration` parameters to configure blue-green upgrade settings.
* Fix `--localdns-config` parameter to handle null values in JSON configuration files gracefully, preventing crashes when DNS override sections are null.

18.0.0b38
+++++++
Expand Down
16 changes: 16 additions & 0 deletions src/aks-preview/azext_aks_preview/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,19 @@ def get_extension_in_allow_list(result):
if _check_if_extension_type_is_in_allow_list(result.extension_type.lower()):
return result
return None


def process_dns_overrides(overrides_dict, target_dict, build_override_func):
"""Helper function to safely process DNS overrides with null checks.

Processes DNS override dictionaries from LocalDNS configuration,
filtering out null values and applying the build function to valid entries.

:param overrides_dict: Dictionary containing DNS overrides (can be None)
:param target_dict: Target dictionary to populate with processed overrides
:param build_override_func: Function to build override objects from dict values
"""
if overrides_dict is not None:
for key, value in overrides_dict.items():
if value is not None:
target_dict[key] = build_override_func(value)
35 changes: 21 additions & 14 deletions src/aks-preview/azext_aks_preview/agentpool_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from azext_aks_preview._helpers import (
get_nodepool_snapshot_by_snapshot_id,
filter_hard_taints,
process_dns_overrides,
)

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

# Build kubeDNSOverrides and vnetDNSOverrides from the localdns_profile
kube_overrides = localdns_profile.get("kubeDNSOverrides")
for key, value in kube_overrides.items():
kube_dns_overrides[key] = build_override(value)

vnet_overrides = localdns_profile.get("vnetDNSOverrides")
for key, value in vnet_overrides.items():
vnet_dns_overrides[key] = build_override(value)
process_dns_overrides(
localdns_profile.get("kubeDNSOverrides"),
kube_dns_overrides,
build_override
)
process_dns_overrides(
localdns_profile.get("vnetDNSOverrides"),
vnet_dns_overrides,
build_override
)

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

# Build kubeDNSOverrides and vnetDNSOverrides from the localdns_profile
kube_overrides = localdns_profile.get("kubeDNSOverrides")
for key, value in kube_overrides.items():
kube_dns_overrides[key] = build_override(value)

vnet_overrides = localdns_profile.get("vnetDNSOverrides")
for key, value in vnet_overrides.items():
vnet_dns_overrides[key] = build_override(value)
process_dns_overrides(
localdns_profile.get("kubeDNSOverrides"),
kube_dns_overrides,
build_override
)
process_dns_overrides(
localdns_profile.get("vnetDNSOverrides"),
vnet_dns_overrides,
build_override
)

agentpool.local_dns_profile = self.models.LocalDNSProfile(
mode=localdns_profile.get("mode"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2684,6 +2684,151 @@ def common_update_blue_green_upgrade_settings(self):
)
self.assertEqual(dec_agentpool_3, ground_truth_agentpool_3)

def common_update_localdns_profile(self):
import tempfile
import json
import os

# Test case 1: LocalDNS config provided - verify method is called
localdns_config = {
"mode": "Required",
"kubeDNSOverrides": {
".": {
"cacheDurationInSeconds": 3600,
"protocol": "PreferUDP"
}
}
}

with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json") as f:
json.dump(localdns_config, f)
f.flush()
config_file_path = f.name

try:
dec_1 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{"localdns_config": config_file_path},
self.resource_type,
self.agentpool_decorator_mode,
)

agentpool_1 = self.create_initialized_agentpool_instance()
dec_1.context.attach_agentpool(agentpool_1)
dec_agentpool_1 = dec_1.update_localdns_profile(agentpool_1)

# Verify that LocalDNS profile was created and assigned
self.assertIsNotNone(dec_agentpool_1.local_dns_profile)
self.assertEqual(dec_agentpool_1.local_dns_profile.mode, "Required")

finally:
os.unlink(config_file_path)

# Test case 2: No LocalDNS config provided - no change
dec_2 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{},
self.resource_type,
self.agentpool_decorator_mode,
)

agentpool_2 = self.create_initialized_agentpool_instance()
original_local_dns_profile = agentpool_2.local_dns_profile
dec_2.context.attach_agentpool(agentpool_2)
dec_agentpool_2 = dec_2.update_localdns_profile(agentpool_2)

# Verify LocalDNS profile wasn't changed
self.assertEqual(dec_agentpool_2.local_dns_profile, original_local_dns_profile)

# Test case 3: LocalDNS config with null values
localdns_config_with_nulls = {
"mode": "Required",
"kubeDNSOverrides": None,
"vnetDNSOverrides": {
".": {
"cacheDurationInSeconds": 1800,
"protocol": "ForceTCP"
}
}
}

with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json") as f:
json.dump(localdns_config_with_nulls, f)
f.flush()
config_file_path = f.name

try:
dec_3 = AKSPreviewAgentPoolUpdateDecorator(
self.cmd,
self.client,
{"localdns_config": config_file_path},
self.resource_type,
self.agentpool_decorator_mode,
)

agentpool_3 = self.create_initialized_agentpool_instance()
dec_3.context.attach_agentpool(agentpool_3)
dec_agentpool_3 = dec_3.update_localdns_profile(agentpool_3)

# Verify that LocalDNS profile was created with null handling
self.assertIsNotNone(dec_agentpool_3.local_dns_profile)
self.assertEqual(dec_agentpool_3.local_dns_profile.mode, "Required")
# kubeDNSOverrides should be empty dict due to null input
self.assertEqual(len(dec_agentpool_3.local_dns_profile.kube_dns_overrides), 0)
# vnetDNSOverrides should have one entry
self.assertEqual(len(dec_agentpool_3.local_dns_profile.vnet_dns_overrides), 1)

finally:
os.unlink(config_file_path)

def common_test_process_dns_overrides_helper(self):
from azext_aks_preview._helpers import process_dns_overrides

# Test the process_dns_overrides utility function functionality

# Test case 1: Valid DNS overrides without nulls
dns_overrides = {
".": {
"cacheDurationInSeconds": 3600,
"protocol": "PreferUDP"
}
}
target_dict = {}

def mock_build_override(override_dict):
return self.models.LocalDNSOverride(
cache_duration_in_seconds=override_dict.get("cacheDurationInSeconds"),
protocol=override_dict.get("protocol")
)

process_dns_overrides(dns_overrides, target_dict, mock_build_override)
self.assertEqual(len(target_dict), 1)
self.assertIn(".", target_dict)

# Test case 2: DNS overrides with null values (should handle gracefully)
dns_overrides_with_nulls = {
".": {
"cacheDurationInSeconds": 1800,
"protocol": None
}
}
target_dict_2 = {}

process_dns_overrides(dns_overrides_with_nulls, target_dict_2, mock_build_override)
self.assertEqual(len(target_dict_2), 1)

# Test case 3: None input (should handle gracefully)
target_dict_3 = {}
process_dns_overrides(None, target_dict_3, mock_build_override)
self.assertEqual(len(target_dict_3), 0)

# Test case 4: Empty input (should handle gracefully)
target_dict_4 = {}
process_dns_overrides({}, target_dict_4, mock_build_override)
self.assertEqual(len(target_dict_4), 0)


class AKSPreviewAgentPoolUpdateDecoratorStandaloneModeTestCase(
AKSPreviewAgentPoolUpdateDecoratorCommonTestCase
Expand Down Expand Up @@ -2721,6 +2866,12 @@ def test_update_upgrade_strategy(self):
def test_update_blue_green_upgrade_settings(self):
self.common_update_blue_green_upgrade_settings()

def test_update_localdns_profile(self):
self.common_update_localdns_profile()

def test_process_dns_overrides_helper(self):
self.common_test_process_dns_overrides_helper()

def test_update_agentpool_profile_preview(self):
import inspect

Expand Down Expand Up @@ -2808,6 +2959,12 @@ def test_update_upgrade_strategy(self):
def test_update_blue_green_upgrade_settings(self):
self.common_update_blue_green_upgrade_settings()

def test_update_localdns_profile(self):
self.common_update_localdns_profile()

def test_process_dns_overrides_helper(self):
self.common_test_process_dns_overrides_helper()

def test_update_agentpool_profile_preview(self):
import inspect

Expand Down
Loading