Skip to content

Commit 52ae5ce

Browse files
committed
{AKS} Add node pool option to provision secondary network interfaces
1 parent 7c393c5 commit 52ae5ce

5 files changed

Lines changed: 92 additions & 0 deletions

File tree

src/aks-preview/azext_aks_preview/_help.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,6 +2291,13 @@
22912291
- name: --localdns-config
22922292
type: string
22932293
short-summary: Set the localDNS Profile for a nodepool with a JSON config file.
2294+
- name: --secondary-network-interfaces
2295+
type: string
2296+
short-summary: Secondary network interface configurations as a JSON string or @<filename>.
2297+
long-summary: |-
2298+
Specify secondary NICs to attach to each node. Accepts inline JSON or @<filename>.
2299+
Example: '[{"type":"Standard","vnetSubnetId":"/subscriptions/.../subnets/mysubnet","enableAcceleratedNetworking":true}]'
2300+
Supported NIC types are "Standard" (requires vnetSubnetId) and "Dynamic".
22942301
- name: --upgrade-strategy
22952302
type: string
22962303
short-summary: Upgrade strategy for the node pool. Allowed values are "Rolling" or "BlueGreen". Default is "Rolling".

src/aks-preview/azext_aks_preview/_params.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,13 @@ def load_arguments(self, _):
22082208
'localdns_config',
22092209
help='Path to a JSON file to configure the local DNS profile for a new nodepool.'
22102210
)
2211+
# secondary network interfaces
2212+
c.argument(
2213+
'secondary_network_interfaces',
2214+
help='Secondary network interface configurations as a JSON string or @<filename> to load from a file. '
2215+
'Example: \'[{"type":"Standard","vnetSubnetId":"/subscriptions/.../subnets/mysubnet"}]\'',
2216+
is_preview=True,
2217+
)
22112218

22122219
with self.argument_context("aks nodepool update") as c:
22132220
c.argument(

src/aks-preview/azext_aks_preview/agentpool_decorator.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from azure.cli.core.util import (
2929
read_file_content,
3030
sdk_no_wait,
31+
shell_safe_json_parse,
3132
)
3233
from azure.core import MatchConditions
3334
from knack.log import get_logger
@@ -961,6 +962,34 @@ def get_localdns_profile(self):
961962
return profile
962963
return None
963964

965+
def get_secondary_network_interfaces(self):
966+
"""Obtain the value of secondary_network_interfaces.
967+
968+
Parse inline JSON or @file reference into a list of AgentPoolNetworkInterface models.
969+
"""
970+
raw = self.raw_param.get("secondary_network_interfaces")
971+
if raw is None:
972+
return None
973+
if isinstance(raw, str):
974+
if raw.startswith("@"):
975+
data = get_file_json(raw[1:])
976+
else:
977+
data = shell_safe_json_parse(raw)
978+
else:
979+
data = raw
980+
if not isinstance(data, list):
981+
raise InvalidArgumentValueError(
982+
"--secondary-network-interfaces must be a JSON array."
983+
)
984+
result = []
985+
for item in data:
986+
result.append(self.models.AgentPoolNetworkInterface(
987+
type=item.get("type"),
988+
vnet_subnet_id=item.get("vnetSubnetId"),
989+
enable_accelerated_networking=item.get("enableAcceleratedNetworking"),
990+
))
991+
return result
992+
964993
def build_localdns_profile(self, agentpool: AgentPool) -> AgentPool:
965994
"""Build local DNS profile for the AgentPool object if provided via --localdns-config."""
966995
localdns_profile = self.get_localdns_profile()
@@ -1304,6 +1333,10 @@ def set_up_agentpool_network_profile(self, agentpool: AgentPool) -> AgentPool:
13041333
if ip_tags:
13051334
agentpool.network_profile.node_public_ip_tags = ip_tags
13061335

1336+
secondary_nics = self.context.get_secondary_network_interfaces()
1337+
if secondary_nics is not None:
1338+
agentpool.network_profile.secondary_network_interfaces = secondary_nics
1339+
13071340
return agentpool
13081341

13091342
def set_up_taints(self, agentpool: AgentPool) -> AgentPool:

src/aks-preview/azext_aks_preview/custom.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,6 +1990,8 @@ def aks_agentpool_add(
19901990
vm_sizes=None,
19911991
# local DNS
19921992
localdns_config=None,
1993+
# secondary network interfaces
1994+
secondary_network_interfaces=None,
19931995
):
19941996
# DO NOT MOVE: get all the original parameters and save them as a dictionary
19951997
raw_parameters = locals()

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,46 @@ def common_get_final_soak_duration(self):
11771177
ctx_3.attach_agentpool(agentpool_3)
11781178
self.assertEqual(ctx_3.get_final_soak_duration(), 1200)
11791179

1180+
def common_get_secondary_network_interfaces(self):
1181+
# default - None
1182+
ctx_1 = AKSPreviewAgentPoolContext(
1183+
self.cmd,
1184+
AKSAgentPoolParamDict({"secondary_network_interfaces": None}),
1185+
self.models,
1186+
DecoratorMode.CREATE,
1187+
self.agentpool_decorator_mode,
1188+
)
1189+
self.assertEqual(ctx_1.get_secondary_network_interfaces(), None)
1190+
1191+
# inline JSON
1192+
ctx_2 = AKSPreviewAgentPoolContext(
1193+
self.cmd,
1194+
AKSAgentPoolParamDict({
1195+
"secondary_network_interfaces": '[{"type":"Standard","vnetSubnetId":"/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/subnet1"}]'
1196+
}),
1197+
self.models,
1198+
DecoratorMode.CREATE,
1199+
self.agentpool_decorator_mode,
1200+
)
1201+
result = ctx_2.get_secondary_network_interfaces()
1202+
self.assertIsNotNone(result)
1203+
self.assertEqual(len(result), 1)
1204+
self.assertEqual(result[0].type, "Standard")
1205+
self.assertEqual(result[0].vnet_subnet_id, "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/subnet1")
1206+
1207+
# invalid JSON - not a list
1208+
ctx_3 = AKSPreviewAgentPoolContext(
1209+
self.cmd,
1210+
AKSAgentPoolParamDict({
1211+
"secondary_network_interfaces": '{"type":"Standard"}'
1212+
}),
1213+
self.models,
1214+
DecoratorMode.CREATE,
1215+
self.agentpool_decorator_mode,
1216+
)
1217+
with self.assertRaises(InvalidArgumentValueError):
1218+
ctx_3.get_secondary_network_interfaces()
1219+
11801220

11811221
class AKSPreviewAgentPoolContextStandaloneModeTestCase(
11821222
AKSPreviewAgentPoolContextCommonTestCase
@@ -1282,6 +1322,9 @@ def test_get_batch_soak_duration(self):
12821322
def test_get_final_soak_duration(self):
12831323
self.common_get_final_soak_duration()
12841324

1325+
def test_get_secondary_network_interfaces(self):
1326+
self.common_get_secondary_network_interfaces()
1327+
12851328

12861329
class AKSPreviewAgentPoolContextManagedClusterModeTestCase(
12871330
AKSPreviewAgentPoolContextCommonTestCase

0 commit comments

Comments
 (0)