Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into k8s-extension/public
  • Loading branch information
action@github.com authored and action@github.com committed Apr 25, 2021
2 parents 5077192 + 4930381 commit dc0c178
Show file tree
Hide file tree
Showing 1,887 changed files with 485,225 additions and 239,584 deletions.
2 changes: 0 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@

/src/alertsmanagement/ @qwordy

/src/synapse/ @idear1203 @aim-for-better

/src/stream-analytics/ @arrownj

/src/databricks/ @fengzhou-msft @bim-msft
Expand Down
3 changes: 3 additions & 0 deletions linter_exclusions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ aks create:
enable_pod_identity_with_kubenet:
rule_exclusions:
- option_length_too_long
assign_kubelet_identity:
rule_exclusions:
- option_length_too_long
aks enable-addons:
parameters:
appgw_watch_namespace:
Expand Down
127 changes: 127 additions & 0 deletions scripts/ci/service_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
"""
Check format of service_name.json. Command and AzureServiceName are required. Others are optional.
Each highest level command group should have reference in service_name.json.
"""
import json

from azure.cli.core import MainCommandsLoader, AzCli
from azure.cli.core._help import AzCliHelp, CliCommandHelpFile
from azure.cli.core.commands import AzCliCommandInvoker, ExtensionCommandSource
from azure.cli.core.parser import AzCliCommandParser
from knack.help import GroupHelpFile


def get_extension_help_files(cli_ctx):

# 1. Create invoker and load command table and arguments. Remember to turn off applicability check.
invoker = cli_ctx.invocation_cls(cli_ctx=cli_ctx, commands_loader_cls=cli_ctx.commands_loader_cls,
parser_cls=cli_ctx.parser_cls, help_cls=cli_ctx.help_cls)
cli_ctx.invocation = invoker

invoker.commands_loader.skip_applicability = True
cmd_table = invoker.commands_loader.load_command_table(None)

# turn off applicability check for all loaders
for loaders in invoker.commands_loader.cmd_to_loader_map.values():
for loader in loaders:
loader.skip_applicability = True

# filter the command table to only get commands from extensions
cmd_table = {k: v for k, v in cmd_table.items() if isinstance(v.command_source, ExtensionCommandSource)}
invoker.commands_loader.command_table = cmd_table
print('FOUND {} command(s) from the extension.'.format(len(cmd_table)))

for cmd_name in cmd_table:
invoker.commands_loader.load_arguments(cmd_name)

invoker.parser.load_command_table(invoker.commands_loader)

# 2. Now load applicable help files
parser_keys = []
parser_values = []
sub_parser_keys = []
sub_parser_values = []
_store_parsers(invoker.parser, parser_keys, parser_values, sub_parser_keys, sub_parser_values)
for cmd, parser in zip(parser_keys, parser_values):
if cmd not in sub_parser_keys:
sub_parser_keys.append(cmd)
sub_parser_values.append(parser)
help_ctx = cli_ctx.help_cls(cli_ctx=cli_ctx)
help_files = []
for cmd, parser in zip(sub_parser_keys, sub_parser_values):
try:
help_file = GroupHelpFile(help_ctx, cmd, parser) if _is_group(parser) \
else CliCommandHelpFile(help_ctx, cmd, parser)
help_file.load(parser)
help_files.append(help_file)
except Exception as ex:
print("Skipped '{}' due to '{}'".format(cmd, ex))
help_files = sorted(help_files, key=lambda x: x.command)
return help_files


def _store_parsers(parser, parser_keys, parser_values, sub_parser_keys, sub_parser_values):
for s in parser.subparsers.values():
parser_keys.append(_get_parser_name(s))
parser_values.append(s)
if _is_group(s):
for c in s.choices.values():
sub_parser_keys.append(_get_parser_name(c))
sub_parser_values.append(c)
_store_parsers(c, parser_keys, parser_values, sub_parser_keys, sub_parser_values)


def _get_parser_name(s):
return (s._prog_prefix if hasattr(s, '_prog_prefix') else s.prog)[3:]


def _is_group(parser):
return getattr(parser, '_subparsers', None) is not None \
or getattr(parser, 'choices', None) is not None


def check():
az_cli = AzCli(cli_name='az',
commands_loader_cls=MainCommandsLoader,
invocation_cls=AzCliCommandInvoker,
parser_cls=AzCliCommandParser,
help_cls=AzCliHelp)
help_files = get_extension_help_files(az_cli)
# High command represents left most word in a command, e.g., vm, disk.
high_command_set = set()
for help_file in help_files:
if help_file.command:
high_command_set.add(help_file.command.split()[0])
print('high_command_set:')
print(high_command_set)

# Load and check service_name.json
with open('src/service_name.json') as f:
service_names = json.load(f)
print('Verifying src/service_name.json')
service_name_map = {}
for service_name in service_names:
command = service_name['Command']
service = service_name['AzureServiceName']
if not command.startswith('az '):
raise Exception('{} does not start with az!'.format(command))
if not service:
raise Exception('AzureServiceName of {} is empty!'.format(command))
service_name_map[command[3:]] = service
print('service_name_map:')
print(service_name_map)

# Check existence in service_name.json
for high_command in high_command_set:
if high_command not in service_name_map:
raise Exception('No entry of {} in service_name.json. Please add one to the file.'.format(high_command))


if __name__ == "__main__":
check()
9 changes: 9 additions & 0 deletions scripts/ci/verify_linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from subprocess import check_output, check_call
from pkg_resources import parse_version

import service_name


def separator_line():
print('-' * 100)
Expand Down Expand Up @@ -160,6 +162,9 @@ def linter_on_external_extension(index_json):
azdev_extension = AzdevExtensionHelper(name)
azdev_extension.linter()

print('Checking service name for external extensions')
service_name.check()

az_extension.remove()


Expand All @@ -181,6 +186,10 @@ def linter_on_internal_extension(modified_files):
azdev_extension = AzdevExtensionHelper(name)
azdev_extension.add_from_code()
azdev_extension.linter()

print('Checking service name for internal extensions')
service_name.check()

azdev_extension.remove()


Expand Down
6 changes: 6 additions & 0 deletions src/aks-preview/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Release History
===============
0.5.10
+++++
* Add `--binding-selector` to AAD pod identity add sub command
* Support using custom kubelet identity
* Support updating Windows password
* Add FIPS support to CLI extension

0.5.9
+++++
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,6 @@
'gitops': 'gitops',
'azure-keyvault-secrets-provider': CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME
}

CONST_MANAGED_IDENTITY_OPERATOR_ROLE = 'Managed Identity Operator'
CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID = 'f1a07417-d97a-45cb-824c-7a7467783830'
40 changes: 38 additions & 2 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
short-summary: User account password to use on windows node VMs.
long-summary: |-
Rules for windows-admin-password:
- Minimum-length: 8 characters
- Minimum-length: 14 characters
- Max-length: 123 characters
- Complexity requirements: 3 out of 4 conditions below need to be fulfilled
* Has lower characters
Expand Down Expand Up @@ -213,6 +213,9 @@
- name: --ppg
type: string
short-summary: The ID of a PPG.
- name: --enable-fips-image
type: bool
short-summary: Use FIPS-enabled OS on agent nodes.
- name: --workspace-resource-id
type: string
short-summary: The resource ID of an existing Log Analytics Workspace to use for storing monitoring data. If not specified, uses the default Log Analytics Workspace if it exists, otherwise creates one.
Expand Down Expand Up @@ -265,7 +268,10 @@
short-summary: Using managed identity to manage cluster resource group. Default value is true, you can explicitly specify "--client-id" and "--secret" to disable managed identity.
- name: --assign-identity
type: string
short-summary: (PREVIEW) Specify an existing user assigned identity to manage cluster resource group.
short-summary: Specify an existing user assigned identity to manage cluster resource group.
- name: --assign-kubelet-identity
type: string
short-summary: Specify an existing user assigned identity for kubelet's usage, which is typically used to pull image from ACR.
- name: --api-server-authorized-ip-ranges
type: string
short-summary: Comma seperated list of authorized apiserver IP ranges. Set to 0.0.0.0/32 to restrict apiserver traffic to node pools.
Expand Down Expand Up @@ -359,6 +365,8 @@
text: az aks create -g MyResourceGroup -n MyManagedCluster --tags "foo=bar" "baz=qux"
- name: Create a kubernetes cluster with EncryptionAtHost enabled.
text: az aks create -g MyResourceGroup -n MyManagedCluster --enable-encryption-at-host
- name: Create a kubernetes cluster with custom control plane identity and kubelet identity.
text: az aks create -g MyResourceGroup -n MyManagedCluster --assign-identity <control-plane-identity-resource-id> --assign-kubelet-identity <kubelet-identity-resource-id>
""".format(sp_cache=AKS_SERVICE_PRINCIPAL_CACHE)

Expand Down Expand Up @@ -500,6 +508,20 @@
- name: --tags
type: string
short-summary: The tags of the managed cluster. The managed cluster instance and all resources managed by the cloud provider will be tagged.
- name: --windows-admin-password
type: string
short-summary: User account password to use on windows node VMs.
long-summary: |-
Rules for windows-admin-password:
- Minimum-length: 14 characters
- Max-length: 123 characters
- Complexity requirements: 3 out of 4 conditions below need to be fulfilled
* Has lower characters
* Has upper characters
* Has a digit
* Has a special character (Regex match [\\W_])
- Disallowed values: "abc@123", "P@$$w0rd", "P@ssw0rd", "P@ssword123", "Pa$$word", "pass@word1", "Password!", "Password1", "Password22", "iloveyou!"
Reference: https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.management.compute.models.virtualmachinescalesetosprofile.adminpassword?view=azure-dotnet
examples:
- name: Enable cluster-autoscaler within node count range [1,5]
text: az aks update --enable-cluster-autoscaler --min-count 1 --max-count 5 -g MyResourceGroup -n MyManagedCluster
Expand Down Expand Up @@ -543,6 +565,8 @@
text: az aks update -g MyResourceGroup -n MyManagedCluster --disable-pod-identity
- name: Update the tags of a kubernetes cluster
text: az aks update -g MyResourceGroup -n MyManagedCLuster --tags "foo=bar" "baz=qux"
- name: Update Windows password of a kubernetes cluster
text: az aks update -g MyResourceGroup -n MyManagedCLuster --windows-admin-password "Repl@cePassw0rd12345678"
"""

helps['aks kollect'] = """
Expand Down Expand Up @@ -813,6 +837,9 @@
- name: --os-type
type: string
short-summary: The OS Type. Linux or Windows.
- name: --enable-fips-image
type: bool
short-summary: Use FIPS-enabled OS on agent nodes.
- name: --enable-cluster-autoscaler -e
type: bool
short-summary: Enable cluster autoscaler.
Expand Down Expand Up @@ -1016,6 +1043,15 @@
crafted: true
"""

helps['aks get-os-options'] = """
type: command
short-summary: Get the OS options available for creating a managed Kubernetes cluster.
examples:
- name: Get the OS options available for creating a managed Kubernetes cluster
text: az aks get-os-options --location westus2
crafted: true
"""

helps['aks get-credentials'] = """
type: command
short-summary: Get access credentials for a managed Kubernetes cluster.
Expand Down
7 changes: 6 additions & 1 deletion src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
validate_taints, validate_priority, validate_eviction_policy, validate_spot_max_price, validate_acr, validate_user,
validate_load_balancer_outbound_ports, validate_load_balancer_idle_timeout, validate_nodepool_tags,
validate_nodepool_labels, validate_vnet_subnet_id, validate_pod_subnet_id, validate_max_surge, validate_assign_identity, validate_addons,
validate_pod_identity_pod_labels, validate_pod_identity_resource_name, validate_pod_identity_resource_namespace)
validate_pod_identity_pod_labels, validate_pod_identity_resource_name, validate_pod_identity_resource_namespace, validate_assign_kubelet_identity)
from ._consts import CONST_OUTBOUND_TYPE_LOAD_BALANCER, \
CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING, CONST_SCALE_SET_PRIORITY_REGULAR, CONST_SCALE_SET_PRIORITY_SPOT, \
CONST_SPOT_EVICTION_POLICY_DELETE, CONST_SPOT_EVICTION_POLICY_DEALLOCATE, \
Expand Down Expand Up @@ -91,6 +91,7 @@ def load_arguments(self, _):
c.argument('ppg')
c.argument('workspace_resource_id')
c.argument('skip_subnet_role_assignment', action='store_true')
c.argument('enable_fips_image', action='store_true', is_preview=True)
c.argument('enable_cluster_autoscaler', action='store_true')
c.argument('uptime_sla', action='store_true')
c.argument('cluster_autoscaler_profile', nargs='+', validator=validate_cluster_autoscaler_profile)
Expand Down Expand Up @@ -127,6 +128,7 @@ def load_arguments(self, _):
c.argument('aci_subnet_name', type=str)
c.argument('enable_encryption_at_host', arg_type=get_three_state_flag(), help='Enable EncryptionAtHost.')
c.argument('enable_secret_rotation', action='store_true')
c.argument('assign_kubelet_identity', type=str, validator=validate_assign_kubelet_identity)
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')

with self.argument_context('aks update') as c:
Expand Down Expand Up @@ -156,6 +158,7 @@ def load_arguments(self, _):
c.argument('disable_pod_identity', action='store_true')
c.argument('enable_secret_rotation', action='store_true')
c.argument('disable_secret_rotation', action='store_true')
c.argument('windows_admin_password', options_list=['--windows-admin-password'])
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')

with self.argument_context('aks scale') as c:
Expand Down Expand Up @@ -200,6 +203,7 @@ def load_arguments(self, _):
c.argument('node_vm_size', options_list=['--node-vm-size', '-s'], completer=get_vm_size_completion_list)
c.argument('max_pods', type=int, options_list=['--max-pods', '-m'])
c.argument('os_type', type=str)
c.argument('enable_fips_image', action='store_true', is_preview=True)
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('priority', arg_type=get_enum_type([CONST_SCALE_SET_PRIORITY_REGULAR, CONST_SCALE_SET_PRIORITY_SPOT]), validator=validate_priority)
Expand Down Expand Up @@ -265,6 +269,7 @@ def load_arguments(self, _):
validator=validate_pod_identity_resource_name('identity_name', required=False))
c.argument('identity_namespace', type=str, options_list=['--namespace'], help='The pod identity namespace.')
c.argument('identity_resource_id', type=str, options_list=['--identity-resource-id'], help='Resource id of the identity to use.')
c.argument('binding_selector', type=str, options_list=['--binding-selector'], help='Optional binding selector to use.')

with self.argument_context('aks pod-identity delete') as c:
c.argument('identity_name', type=str, options_list=['--name', '-n'], default=None, required=True,
Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,3 +468,12 @@ def validate_pod_identity_resource_namespace(namespace):
if not namespace_value:
# namespace cannot be empty
raise CLIError('--namespace is required')


def validate_assign_kubelet_identity(namespace):
if namespace.assign_kubelet_identity is not None:
if namespace.assign_kubelet_identity == '':
return
from msrestazure.tools import is_valid_resource_id
if not is_valid_resource_id(namespace.assign_kubelet_identity):
raise CLIError("--assign-kubelet-identity is not a valid Azure resource ID.")
1 change: 1 addition & 0 deletions src/aks-preview/azext_aks_preview/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def load_command_table(self, _):
g.wait_command('wait')
g.command('stop', 'stop', supports_no_wait=True)
g.command('start', 'start', supports_no_wait=True)
g.custom_command('get-os-options', 'aks_get_os_options')

# AKS container service commands
with self.command_group('aks', container_services_sdk, client_factory=cf_container_services) as g:
Expand Down
Loading

0 comments on commit dc0c178

Please sign in to comment.