Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
18 changes: 18 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,12 @@
- name: --enable-vpa
type: bool
short-summary: Enable vertical pod autoscaler for cluster.
- name: --nodepool-allowed-host-ports
type: string
short-summary: Expose host ports on the node pool. When specified, format should be a comma-separated list of ranges with protocol, eg. 80/TCP,443/TCP,4000-5000/TCP.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the input is a list, it is a better way to define the parameter with nargs='+' and it is not necessary to manually separate the string. After defining with that, the input should be a space-separated list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated. TIL thanks

- name: --nodepool-asg-ids
type: string
short-summary: The IDs of the application security groups to which the node pool's network interface should belong. When specified, format should be a comma-separated list of IDs.
examples:
- name: Create a Kubernetes cluster with an existing SSH public key.
Expand Down Expand Up @@ -1516,6 +1522,12 @@
- name: --gpu-instance-profile
type: string
short-summary: GPU instance profile to partition multi-gpu Nvidia GPUs.
- name: --allowed-host-ports
type: string
short-summary: Expose host ports on the node pool. When specified, format should be a comma-separated list of ranges with protocol, eg. 80/TCP,443/TCP,4000-5000/TCP.
- name: --asg-ids
type: string
short-summary: The IDs of the application security groups to which the node pool's network interface should belong. When specified, format should be a comma-separated list of IDs.
examples:
- name: Create a nodepool in an existing AKS cluster with ephemeral os enabled.
text: az aks nodepool add -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --node-osdisk-type Ephemeral --node-osdisk-size 48
Expand Down Expand Up @@ -1607,6 +1619,12 @@
- name: --aks-custom-headers
type: string
short-summary: Comma-separated key-value pairs to specify custom headers.
- name: --allowed-host-ports
type: string
short-summary: Expose host ports on the node pool. When specified, format should be a comma-separated list of ranges with protocol, eg. 80/TCP,443/TCP,4000-5000/TCP.
- name: --asg-ids
type: string
short-summary: The IDs of the application security groups to which the node pool's network interface should belong. When specified, format should be a comma-separated list of IDs.
examples:
- name: Reconcile the nodepool back to its current state.
text: az aks nodepool update -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster
Expand Down
9 changes: 8 additions & 1 deletion src/azure-cli/azure/cli/command_modules/acs/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
validate_snapshot_name, validate_spot_max_price, validate_ssh_key,
validate_nodepool_taints, validate_vm_set_type, validate_vnet_subnet_id, validate_k8s_support_plan,
validate_utc_offset, validate_start_date, validate_start_time,
validate_force_upgrade_disable_and_enable_parameters)
validate_force_upgrade_disable_and_enable_parameters,
validate_allowed_host_ports, validate_application_security_groups)
from azure.cli.core.commands.parameters import (
edge_zone_type, file_type, get_enum_type,
get_resource_name_completion_list, get_three_state_flag, name_type,
Expand Down Expand Up @@ -329,6 +330,8 @@ def load_arguments(self, _):
c.argument('enable_windows_recording_rules', action='store_true')
# misc
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')
c.argument('nodepool_allowed_host_ports', validator=validate_allowed_host_ports, help="allowed host ports for agentpool")
c.argument('nodepool_asg_ids', validator=validate_application_security_groups, help="application security groups for agentpool")

with self.argument_context('aks update') as c:
# managed cluster paramerters
Expand Down Expand Up @@ -567,6 +570,8 @@ def load_arguments(self, _):
c.argument('linux_os_config')
c.argument('host_group_id', validator=validate_host_group_id)
c.argument('gpu_instance_profile', arg_type=get_enum_type(gpu_instance_profiles))
c.argument('allowed_host_ports', validator=validate_allowed_host_ports)
c.argument('asg_ids', validator=validate_application_security_groups)

with self.argument_context('aks nodepool update', resource_type=ResourceType.MGMT_CONTAINERSERVICE, operation_group='agent_pools') as c:
c.argument('enable_cluster_autoscaler', options_list=[
Expand All @@ -584,6 +589,8 @@ def load_arguments(self, _):
c.argument('drain_timeout', type=int)
c.argument('mode', get_enum_type(node_mode_types))
c.argument('scale_down_mode', arg_type=get_enum_type(scale_down_modes))
c.argument('allowed_host_ports', validator=validate_allowed_host_ports)
c.argument('asg_ids', validator=validate_application_security_groups)

with self.argument_context('aks nodepool upgrade') as c:
c.argument('max_surge', validator=validate_max_surge)
Expand Down
32 changes: 32 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,3 +735,35 @@ def validate_start_time(namespace):
def validate_force_upgrade_disable_and_enable_parameters(namespace):
if namespace.disable_force_upgrade and namespace.enable_force_upgrade:
raise MutuallyExclusiveArgumentError('Providing both --disable-force-upgrade and --enable-force-upgrade flags is invalid')


def validate_allowed_host_ports(namespace):
if hasattr(namespace, "nodepool_allowed_host_ports"):
host_ports = namespace.nodepool_allowed_host_ports
else:
host_ports = namespace.allowed_host_ports
if not host_ports:
return

regex = re.compile(r'^((\d+)|(\d+-\d+))/(tcp|udp)$')
for port_range in host_ports.split(","):
found = regex.findall(port_range)
if found:
continue
raise InvalidArgumentValueError(
"--allowed-host-ports must be a comma-separated list of port ranges in the format of <port-range>/<protocol>"
)


def validate_application_security_groups(namespace):
if hasattr((namespace), "nodepool_asg_ids"):
asg_ids = namespace.nodepool_asg_ids
else:
asg_ids = namespace.asg_ids
if not asg_ids:
return

from msrestazure.tools import is_valid_resource_id
for asg in asg_ids.split(","):
if not is_valid_resource_id(asg):
raise InvalidArgumentValueError(asg + " is not a valid Azure resource ID.")
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
# type variables
AgentPool = TypeVar("AgentPool")
AgentPoolsOperations = TypeVar("AgentPoolsOperations")
PortRange = TypeVar("PortRange")
Snapshot = TypeVar("Snapshot")
KubeletConfig = TypeVar("KubeletConfig")
LinuxOSConfig = TypeVar("LinuxOSConfig")
Expand Down Expand Up @@ -1256,6 +1257,49 @@ def get_gpu_instance_profile(self) -> Union[str, None]:
# this parameter does not need validation
return gpu_instance_profile

def get_asg_ids(self) -> Union[List[str], None]:
if self.agentpool_decorator_mode == AgentPoolDecoratorMode.MANAGED_CLUSTER:
asg_ids = self.raw_param.get('nodepool_asg_ids')
else:
asg_ids = self.raw_param.get('asg_ids')

if asg_ids is None:
return None
if asg_ids == '':
return []

return asg_ids.split(',')

def get_allowed_host_ports(self) -> Union[List[PortRange], None]:
if self.agentpool_decorator_mode == AgentPoolDecoratorMode.MANAGED_CLUSTER:
ports = self.raw_param.get('nodepool_allowed_host_ports')
else:
ports = self.raw_param.get('allowed_host_ports')

if ports is None:
return None
if ports == '':
return []

ports = ports.split(',')
port_ranges = []
import re
regex = re.compile(r'^((\d+)|((\d+)-(\d+)))/(tcp|udp)$')
for port in ports:
r = regex.findall(port)
if r[0][1] != '':
# single port
port_start, port_end = int(r[0][1]), int(r[0][1])
else:
# port range
port_start, port_end = int(r[0][3]), int(r[0][4])
port_ranges.append(self.models.PortRange(
port_start=port_start,
port_end=port_end,
protocol=r[0][5].upper(),
))
return port_ranges


class AKSAgentPoolAddDecorator:
def __init__(
Expand Down Expand Up @@ -1540,6 +1584,17 @@ def set_up_gpu_properties(self, agentpool: AgentPool) -> AgentPool:
agentpool.gpu_instance_profile = self.context.get_gpu_instance_profile()
return agentpool

def set_up_agentpool_network_profile(self, agentpool: AgentPool) -> AgentPool:
self._ensure_agentpool(agentpool)

asg_ids = self.context.get_asg_ids()
allowed_host_ports = self.context.get_allowed_host_ports()
if allowed_host_ports is not None:
agentpool.network_profile = self.models.AgentPoolNetworkProfile()
agentpool.network_profile.allowed_host_ports = allowed_host_ports
agentpool.network_profile.application_security_groups = asg_ids
return agentpool

def construct_agentpool_profile_default(self, bypass_restore_defaults: bool = False) -> AgentPool:
"""The overall controller used to construct the AgentPool profile by default.

Expand Down Expand Up @@ -1574,6 +1629,8 @@ def construct_agentpool_profile_default(self, bypass_restore_defaults: bool = Fa
agentpool = self.set_up_custom_node_config(agentpool)
# set up gpu instance profile
agentpool = self.set_up_gpu_properties(agentpool)
# set up agentpool network profile
agentpool = self.set_up_agentpool_network_profile(agentpool)
# restore defaults
if not bypass_restore_defaults:
agentpool = self._restore_defaults_in_agentpool(agentpool)
Expand Down Expand Up @@ -1777,6 +1834,19 @@ def update_vm_properties(self, agentpool: AgentPool) -> AgentPool:
agentpool.mode = mode
return agentpool

def update_network_profile(self, agentpool: AgentPool) -> AgentPool:
self._ensure_agentpool(agentpool)

asg_ids = self.context.get_asg_ids()
allowed_host_ports = self.context.get_allowed_host_ports()
if asg_ids or allowed_host_ports:
agentpool.network_profile = self.models.AgentPoolNetworkProfile()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could overwrite existing fields in network_profile by creating a new one. I will fix it in a following PR.

if asg_ids is not None:
agentpool.network_profile.application_security_groups = asg_ids
if allowed_host_ports is not None:
agentpool.network_profile.allowed_host_ports = allowed_host_ports
Comment on lines +1836 to +1841
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this profile support partial update? For example, for an existing nodepool network profile, both application_security_groups and allowed_host_ports have been configured. Now the user only specifies application_security_groups when updating. Then the request body will be application_security_groups=new value, allowed_host_ports=null. Is this a valid scenario and the behavior expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this profile support partial update?

No. If this feature is turned on, you’ve got to set both values when updating the network profile. You can change ASGs from your own to a managed one if you don’t specify ‘–asg-ids’, and also the other way round.

return agentpool

def update_agentpool_profile_default(self, agentpools: List[AgentPool] = None) -> AgentPool:
"""The overall controller used to update AgentPool profile by default.

Expand All @@ -1795,6 +1865,8 @@ def update_agentpool_profile_default(self, agentpools: List[AgentPool] = None) -
agentpool = self.update_upgrade_settings(agentpool)
# update misc vm properties
agentpool = self.update_vm_properties(agentpool)
# update network profile
agentpool = self.update_network_profile(agentpool)
return agentpool

def update_agentpool(self, agentpool: AgentPool) -> AgentPool:
Expand Down
6 changes: 6 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ def aks_create(
nodepool_tags=None,
nodepool_labels=None,
nodepool_taints=None,
nodepool_allowed_host_ports=None,
nodepool_asg_ids=None,
node_osdisk_type=None,
node_osdisk_size=None,
vm_set_type=None,
Expand Down Expand Up @@ -2193,6 +2195,8 @@ def aks_agentpool_add(
aks_custom_headers=None,
host_group_id=None,
gpu_instance_profile=None,
allowed_host_ports=None,
asg_ids=None,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -2237,6 +2241,8 @@ def aks_agentpool_update(
scale_down_mode=None,
no_wait=False,
aks_custom_headers=None,
allowed_host_ports=None,
asg_ids=None,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ aks create:
node_os_upgrade_channel:
rule_exclusions:
- option_length_too_long
nodepool_allowed_host_ports:
rule_exclusions:
- option_length_too_long

aks enable-addons:
parameters:
Expand Down
Loading