Skip to content

Commit

Permalink
[AKS] add support for creation time node labels (#12418)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiaofang Zhang committed Mar 4, 2020
1 parent 06a83a4 commit e42d9f7
Show file tree
Hide file tree
Showing 8 changed files with 1,704 additions and 787 deletions.
3 changes: 3 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 @@ -617,6 +617,9 @@
- name: --node-taints
type: string
short-summary: The node taints for the node pool. You can't change the node taints through CLI after the node pool is created.
- name: --labels
type: string
short-summary: The node labels for the node pool. You can't change the node labels through CLI after the node pool is created. See https://aka.ms/node-labels for syntax of labels.
"""

helps['aks nodepool delete'] = """
Expand Down
4 changes: 3 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 @@ -21,7 +21,7 @@
validate_list_of_integers, validate_ssh_key, validate_connector_name, validate_max_pods, validate_nodes_count,
validate_nodepool_name, validate_vm_set_type, validate_load_balancer_sku, validate_load_balancer_outbound_ips,
validate_load_balancer_outbound_ip_prefixes, validate_taints, validate_ip_ranges, validate_acr, validate_nodepool_tags,
validate_load_balancer_outbound_ports, validate_load_balancer_idle_timeout, validate_vnet_subnet_id)
validate_load_balancer_outbound_ports, validate_load_balancer_idle_timeout, validate_vnet_subnet_id, validate_nodepool_labels)

aci_connector_os_type = ['Windows', 'Linux', 'Both']

Expand Down Expand Up @@ -200,6 +200,7 @@ def load_arguments(self, _):
c.argument('attach_acr', acr_arg_type)
c.argument('enable_private_cluster', action='store_true')
c.argument('nodepool_tags', nargs='*', validator=validate_nodepool_tags, help='space-separated tags: key[=value] [key[=value] ...]. Use "" to clear existing tags.')
c.argument('nodepool_labels', nargs='*', validator=validate_nodepool_labels, help='space-separated labels: key[=value] [key[=value] ...]. You can not change the node labels through CLI after creation. See https://aka.ms/node-labels for syntax of labels.')

with self.argument_context('aks update') as c:
c.argument('attach_acr', acr_arg_type, validator=validate_acr)
Expand Down Expand Up @@ -288,6 +289,7 @@ def load_arguments(self, _):
c.argument('enable_cluster_autoscaler', options_list=["--enable-cluster-autoscaler", "-e"], action='store_true')
c.argument('node_taints', type=str, validator=validate_taints)
c.argument('tags', tags_type)
c.argument('labels', nargs='*', validator=validate_nodepool_labels)

for scope in ['aks nodepool show', 'aks nodepool delete', 'aks nodepool scale', 'aks nodepool upgrade', 'aks nodepool update']:
with self.argument_context(scope) as c:
Expand Down
72 changes: 72 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 @@ -259,3 +259,75 @@ def validate_vnet_subnet_id(namespace):
from msrestazure.tools import is_valid_resource_id
if not is_valid_resource_id(namespace.vnet_subnet_id):
raise CLIError("--vnet-subnet-id is not a valid Azure resource ID.")


def validate_nodepool_labels(namespace):
"""Validates that provided node labels is a valid format"""

if hasattr(namespace, 'nodepool_labels'):
labels = namespace.nodepool_labels
else:
labels = namespace.labels

if labels is None:
return

if isinstance(labels, list):
labels_dict = {}
for item in labels:
labels_dict.update(validate_label(item))
after_validation_labels = labels_dict
else:
after_validation_labels = validate_label(labels)

if hasattr(namespace, 'nodepool_labels'):
namespace.nodepool_labels = after_validation_labels
else:
namespace.labels = after_validation_labels


def validate_label(label):
"""Validates that provided label is a valid format"""
prefix_regex = re.compile(r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$")
name_regex = re.compile(r"^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$")
value_regex = re.compile(r"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$")

if label == "":
return {}
kv = label.split('=')
if len(kv) != 2:
raise CLIError("Invalid label: %s. Label definition must be of format name=value." % label)
name_parts = kv[0].split('/')
if len(name_parts) == 1:
name = name_parts[0]
elif len(name_parts) == 2:
prefix = name_parts[0]
if not prefix or len(prefix) > 253:
raise CLIError("Invalid label: %s. Label prefix can't be empty or more than 253 chars." % label)
if not prefix_regex.match(prefix):
raise CLIError("Invalid label: %s. Prefix part a DNS-1123 label must consist of lower case alphanumeric "
"characters or '-', and must start and end with an alphanumeric character" % label)
name = name_parts[1]
else:
raise CLIError("Invalid label: %s. A qualified name must consist of alphanumeric characters, '-', '_' "
"or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or "
"'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' "
"(e.g. 'example.com/MyName')" % label)

# validate label name
if not name or len(name) > 63:
raise CLIError("Invalid label: %s. Label name can't be empty or more than 63 chars." % label)
if not name_regex.match(name):
raise CLIError("Invalid label: %s. A qualified name must consist of alphanumeric characters, '-', '_' "
"or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or "
"'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' (e.g. "
"'example.com/MyName')" % label)

# validate label value
if len(kv[1]) > 63:
raise CLIError("Invalid label: %s. Label must be more than 63 chars." % label)
if not value_regex.match(kv[1]):
raise CLIError("Invalid label: %s. A valid label must be an empty string or consist of alphanumeric "
"characters, '-', '_' or '.', and must start and end with an alphanumeric character" % label)

return {kv[0]: kv[1]}
4 changes: 4 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 @@ -1647,6 +1647,7 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
node_count=3,
nodepool_name="nodepool1",
nodepool_tags=None,
nodepool_labels=None,
service_principal=None, client_secret=None,
no_ssh_key=False,
disable_rbac=None,
Expand Down Expand Up @@ -1701,6 +1702,7 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint:
agent_pool_profile = ManagedClusterAgentPoolProfile(
name=_trim_nodepoolname(nodepool_name), # Must be 12 chars or less before ACS RP adds to it
tags=nodepool_tags,
node_labels=nodepool_labels,
count=int(node_count),
vm_size=node_vm_size,
os_type="Linux",
Expand Down Expand Up @@ -2717,6 +2719,7 @@ def aks_agentpool_add(cmd, client, resource_group_name, cluster_name, nodepool_n
enable_cluster_autoscaler=False,
node_taints=None,
tags=None,
labels=None,
no_wait=False):
instances = client.list(resource_group_name, cluster_name)
for agentpool_profile in instances:
Expand All @@ -2742,6 +2745,7 @@ def aks_agentpool_add(cmd, client, resource_group_name, cluster_name, nodepool_n
agent_pool = AgentPool(
name=nodepool_name,
tags=tags,
node_labels=labels,
count=int(node_count),
vm_size=node_vm_size,
os_type=os_type,
Expand Down
Loading

0 comments on commit e42d9f7

Please sign in to comment.