Skip to content

Commit 111cfcd

Browse files
author
Jim Minter
committed
First implementation of az aks prepared-image-specification
1 parent 8929ef4 commit 111cfcd

15 files changed

Lines changed: 6967 additions & 3 deletions

‎src/aks-preview/HISTORY.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
15+
21.0.0b5
16+
+++++++
17+
* `az aks prepared-image-specification`: Add new command.
1418
* `az aks upgrade`: Fix `--node-image-only` to skip Machines mode agent pools, which do not support node image version upgrade.
1519

1620
21.0.0b4

‎src/aks-preview/azext_aks_preview/__init__.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
# pylint: disable=unused-import
1111
import azext_aks_preview._help
12-
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW
12+
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW, CUSTOM_MGMT_AKS_PIS_PREVIEW
1313

1414

1515
def register_aks_preview_resource_type():
@@ -19,6 +19,12 @@ def register_aks_preview_resource_type():
1919
None,
2020
)
2121

22+
register_resource_type(
23+
"latest",
24+
CUSTOM_MGMT_AKS_PIS_PREVIEW,
25+
None,
26+
)
27+
2228

2329
class ContainerServiceCommandsLoader(AzCommandsLoader):
2430

‎src/aks-preview/azext_aks_preview/_client_factory.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
CUSTOM_MGMT_AKS_PREVIEW = CustomResourceType('azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks',
1414
'ContainerServiceClient')
1515

16+
CUSTOM_MGMT_AKS_PIS_PREVIEW = CustomResourceType('azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks_pis',
17+
'ContainerServiceClient')
18+
1619
# Note: cf_xxx, as the client_factory option value of a command group at command declaration, it should ignore
1720
# parameters other than cli_ctx; get_xxx_client is used as the client of other services in the command implementation,
1821
# and usually accepts subscription_id as a parameter to reconfigure the subscription when sending the request
@@ -23,6 +26,10 @@ def get_container_service_client(cli_ctx, subscription_id=None):
2326
return get_mgmt_service_client(cli_ctx, CUSTOM_MGMT_AKS_PREVIEW, subscription_id=subscription_id)
2427

2528

29+
def get_container_service_pis_client(cli_ctx, subscription_id=None):
30+
return get_mgmt_service_client(cli_ctx, CUSTOM_MGMT_AKS_PIS_PREVIEW, subscription_id=subscription_id)
31+
32+
2633
def cf_container_services(cli_ctx, *_):
2734
return get_container_service_client(cli_ctx).container_services
2835

@@ -159,3 +166,7 @@ def cf_jwt_authenticators(cli_ctx, *_):
159166

160167
def cf_vm_skus(cli_ctx, *_):
161168
return get_container_service_client(cli_ctx).vm_skus
169+
170+
171+
def cf_prepared_image_specifications(cli_ctx, *_, subscription_id=None):
172+
return get_container_service_pis_client(cli_ctx, subscription_id=subscription_id).prepared_image_specifications

‎src/aks-preview/azext_aks_preview/_help.py‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4708,3 +4708,62 @@
47084708
- name: Show a specific JWT authenticator configuration
47094709
text: az aks jwtauthenticator show -g MyResourceGroup --cluster-name MyCluster --name myjwt
47104710
"""
4711+
4712+
helps['aks prepared-image-specification'] = """
4713+
type: group
4714+
short-summary: Commands to manage prepared image specifications.
4715+
"""
4716+
4717+
helps['aks prepared-image-specification create'] = """
4718+
type: command
4719+
short-summary: Create a new prepared image specification.
4720+
examples:
4721+
- name: Create a new prepared image specification specifying a container image.
4722+
text: az aks prepared-image-specification create -g MyResourceGroup -n MyPIS --version MyVersion --container-images myacr.azurecr.io/myimage:latest
4723+
- name: Create a new prepared image specification specifying a customization script.
4724+
text: az aks prepared-image-specification create -g MyResourceGroup -n MyPIS --version MyVersion --customization-scripts '[{"name":"myscript","script":"/bin/true","scriptType":"Bash","executionPoint":"NodeImageBuildTime"}]'
4725+
- name: Create a new prepared image specification specifying a managed identity.
4726+
text: az aks prepared-image-specification create -g MyResourceGroup -n MyPIS --version MyVersion --assign-identity /subscriptions/MySubscription/resourceGroups/AnotherResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/MyIdentity
4727+
- name: Create a new prepared image specification specifying tags.
4728+
text: az aks prepared-image-specification create -g MyResourceGroup -n MyPIS --version MyVersion --tags k1=v1 k2=v2
4729+
"""
4730+
4731+
helps['aks prepared-image-specification update'] = """
4732+
type: command
4733+
short-summary: Update a prepared image specification.
4734+
"""
4735+
4736+
helps['aks prepared-image-specification delete'] = """
4737+
type: command
4738+
short-summary: Delete a prepared image specification.
4739+
"""
4740+
4741+
helps['aks prepared-image-specification list'] = """
4742+
type: command
4743+
short-summary: List prepared image specifications.
4744+
"""
4745+
4746+
helps['aks prepared-image-specification show'] = """
4747+
type: command
4748+
short-summary: Show a prepared image specification.
4749+
"""
4750+
4751+
helps['aks prepared-image-specification version'] = """
4752+
type: group
4753+
short-summary: Commands to manage prepared image specification versions.
4754+
"""
4755+
4756+
helps['aks prepared-image-specification version delete'] = """
4757+
type: command
4758+
short-summary: Delete a prepared image specification version.
4759+
"""
4760+
4761+
helps['aks prepared-image-specification version list'] = """
4762+
type: command
4763+
short-summary: List prepared image specification versions.
4764+
"""
4765+
4766+
helps['aks prepared-image-specification version show'] = """
4767+
type: command
4768+
short-summary: Show a prepared image specification version.
4769+
"""

‎src/aks-preview/azext_aks_preview/_params.py‎

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
tags_type,
3434
zones_type,
3535
)
36+
from azure.cli.core.commands.validators import validate_file_or_dict
3637
from azext_aks_preview._validators import (
3738
validate_nat_gateway_managed_outbound_ipv6_count,
3839
validate_nat_gateway_v2_params,
@@ -251,6 +252,7 @@
251252
validate_drain_batch_size,
252253
validate_resource_group_parameter,
253254
validate_location_resource_group_cluster_parameters,
255+
validate_prepared_image_specification_id,
254256
)
255257
from azext_aks_preview.azurecontainerstorage._consts import (
256258
CONST_ACSTOR_ALL,
@@ -1298,6 +1300,15 @@ def load_arguments(self, _):
12981300
is_preview=True,
12991301
help="Enable continuous control plane and addon monitor for the cluster.",
13001302
)
1303+
# prepared image specification
1304+
c.argument(
1305+
'prepared_image_specification_id',
1306+
options_list=["--prepared-image-specification-id", "--pis-id"],
1307+
is_preview=True,
1308+
validator=validate_prepared_image_specification_id,
1309+
help='The resource ID of the prepared image specification to use for provisioning nodes in the default '
1310+
'node pool.'
1311+
)
13011312

13021313
with self.argument_context("aks update") as c:
13031314
# managed cluster paramerters
@@ -2260,6 +2271,14 @@ def load_arguments(self, _):
22602271
'Example: \'[{"type":"Standard","vnetSubnetId":"/subscriptions/.../subnets/mysubnet"}]\'',
22612272
is_preview=True,
22622273
)
2274+
# prepared image specification
2275+
c.argument(
2276+
'prepared_image_specification_id',
2277+
options_list=["--prepared-image-specification-id", "--pis-id"],
2278+
is_preview=True,
2279+
validator=validate_prepared_image_specification_id,
2280+
help='The resource ID of the prepared image specification to use for provisioning nodes in the node pool.'
2281+
)
22632282

22642283
with self.argument_context("aks nodepool update") as c:
22652284
c.argument(
@@ -2384,6 +2403,14 @@ def load_arguments(self, _):
23842403
is_preview=True,
23852404
help="Specify the GPU Multi-Instance GPU (MIG) strategy. Allowed values: Single, Mixed.",
23862405
)
2406+
# prepared image specification
2407+
c.argument(
2408+
'prepared_image_specification_id',
2409+
options_list=["--prepared-image-specification-id", "--pis-id"],
2410+
is_preview=True,
2411+
validator=validate_prepared_image_specification_id,
2412+
help='The resource ID of the prepared image specification to use for provisioning nodes in the node pool.'
2413+
)
23872414

23882415
with self.argument_context("aks nodepool upgrade") as c:
23892416
# upgrade strategy
@@ -3450,6 +3477,91 @@ def load_arguments(self, _):
34503477
help="Show all VM SKU information including those not available for the current subscription.",
34513478
)
34523479

3480+
with self.argument_context("aks prepared-image-specification create") as c:
3481+
c.argument(
3482+
"name",
3483+
options_list=["--name", "-n"],
3484+
required=True,
3485+
help="The prepared image specification name.",
3486+
)
3487+
c.argument(
3488+
"container_images",
3489+
nargs="+",
3490+
help="Container images.",
3491+
)
3492+
c.argument(
3493+
"customization_scripts",
3494+
type=validate_file_or_dict,
3495+
help="Customization scripts. Expected value: json-string/@json-file.",
3496+
)
3497+
c.argument(
3498+
"assign_identity",
3499+
validator=validate_assign_identity,
3500+
help="Specify an existing user assigned identity.",
3501+
)
3502+
c.argument(
3503+
"version",
3504+
required=True,
3505+
help="The prepared image specification version.",
3506+
)
3507+
3508+
with self.argument_context("aks prepared-image-specification update") as c:
3509+
c.argument(
3510+
"name",
3511+
options_list=["--name", "-n"],
3512+
required=True,
3513+
help="The prepared image specification name.",
3514+
)
3515+
3516+
with self.argument_context("aks prepared-image-specification delete") as c:
3517+
c.argument(
3518+
"name",
3519+
options_list=["--name", "-n"],
3520+
required=True,
3521+
help="The prepared image specification name.",
3522+
)
3523+
3524+
with self.argument_context("aks prepared-image-specification show") as c:
3525+
c.argument(
3526+
"name",
3527+
options_list=["--name", "-n"],
3528+
required=True,
3529+
help="The prepared image specification name.",
3530+
)
3531+
3532+
with self.argument_context("aks prepared-image-specification version delete") as c:
3533+
c.argument(
3534+
"pis_name",
3535+
required=True,
3536+
help="The prepared image specification name.",
3537+
)
3538+
c.argument(
3539+
"name",
3540+
options_list=["--name", "-n"],
3541+
required=True,
3542+
help="The version name.",
3543+
)
3544+
3545+
with self.argument_context("aks prepared-image-specification version list") as c:
3546+
c.argument(
3547+
"pis_name",
3548+
required=True,
3549+
help="The prepared image specification name.",
3550+
)
3551+
3552+
with self.argument_context("aks prepared-image-specification version show") as c:
3553+
c.argument(
3554+
"pis_name",
3555+
required=True,
3556+
help="The prepared image specification name.",
3557+
)
3558+
c.argument(
3559+
"name",
3560+
options_list=["--name", "-n"],
3561+
required=True,
3562+
help="The version name.",
3563+
)
3564+
34533565

34543566
def _get_default_install_location(exe_name):
34553567
system = platform.system()

‎src/aks-preview/azext_aks_preview/_validators.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,3 +1230,20 @@ def validate_nat_gateway_v2_params(namespace):
12301230
"--nat-gateway-outbound-ip-prefixes are only "
12311231
"valid with --outbound-type managedNATGatewayV2."
12321232
)
1233+
1234+
1235+
def validate_prepared_image_specification_id(namespace):
1236+
if namespace.prepared_image_specification_id:
1237+
if not is_valid_resource_id(namespace.prepared_image_specification_id):
1238+
raise InvalidArgumentValueError(
1239+
"--prepared-image-specification-id is not a valid Azure resource ID."
1240+
)
1241+
parsed = parse_resource_id(namespace.prepared_image_specification_id)
1242+
resource_type = (parsed.get("type", "") + "/" + parsed.get("resource_type", "")).lower()
1243+
resource_namespace = parsed.get("namespace", "").lower()
1244+
if resource_namespace != "microsoft.containerservice" or \
1245+
resource_type != "preparedimagespecifications/versions":
1246+
raise InvalidArgumentValueError(
1247+
"--prepared-image-specification-id must be a resource ID of type "
1248+
"Microsoft.ContainerService/preparedImageSpecifications/versions."
1249+
)

‎src/aks-preview/azext_aks_preview/agentpool_decorator.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,12 @@ def get_if_none_match(self) -> str:
905905
"""
906906
return self.raw_param.get("if_none_match")
907907

908+
def get_prepared_image_specification_id(self) -> Union[str, None]:
909+
"""Obtain the value of prepared_image_specification_id.
910+
:return: str or None
911+
"""
912+
return self.raw_param.get('prepared_image_specification_id')
913+
908914
def get_gateway_prefix_size(self) -> Union[int, None]:
909915
"""Obtain the value of gateway_prefix_size.
910916
:return: int or None
@@ -1660,6 +1666,18 @@ def set_up_localdns_profile(self, agentpool: AgentPool) -> AgentPool:
16601666
self._ensure_agentpool(agentpool)
16611667
return self.context.build_localdns_profile(agentpool)
16621668

1669+
def set_up_prepared_image_specification(self, agentpool: AgentPool) -> AgentPool:
1670+
"""Set up prepared image specification profile for the AgentPool object."""
1671+
self._ensure_agentpool(agentpool)
1672+
1673+
prepared_image_specification_id = self.context.get_prepared_image_specification_id()
1674+
if prepared_image_specification_id is not None:
1675+
agentpool.prepared_image_specification_profile = self.models.PreparedImageSpecificationProfile( # pylint: disable=no-member
1676+
prepared_image_specification_id=prepared_image_specification_id,
1677+
)
1678+
1679+
return agentpool
1680+
16631681
def construct_agentpool_profile_preview(self) -> AgentPool:
16641682
"""The overall controller used to construct the preview AgentPool profile.
16651683
@@ -1723,6 +1741,8 @@ def construct_agentpool_profile_preview(self) -> AgentPool:
17231741
agentpool = self.set_up_upgrade_strategy(agentpool)
17241742
# set up blue green upgrade settings
17251743
agentpool = self.set_up_blue_green_upgrade_settings(agentpool)
1744+
# set up prepared image specification
1745+
agentpool = self.set_up_prepared_image_specification(agentpool)
17261746
# DO NOT MOVE: keep this at the bottom, restore defaults
17271747
agentpool = self._restore_defaults_in_agentpool(agentpool)
17281748
return agentpool
@@ -2071,6 +2091,21 @@ def update_upgrade_strategy(self, agentpool: AgentPool) -> AgentPool:
20712091

20722092
return agentpool
20732093

2094+
def update_prepared_image_specification(self, agentpool: AgentPool) -> AgentPool:
2095+
"""Update prepared image specification profile for the AgentPool object."""
2096+
self._ensure_agentpool(agentpool)
2097+
2098+
prepared_image_specification_id = self.context.get_prepared_image_specification_id()
2099+
if prepared_image_specification_id is not None:
2100+
if prepared_image_specification_id == "":
2101+
prepared_image_specification_id = None
2102+
2103+
agentpool.prepared_image_specification_profile = self.models.PreparedImageSpecificationProfile( # pylint: disable=no-member
2104+
prepared_image_specification_id=prepared_image_specification_id,
2105+
)
2106+
2107+
return agentpool
2108+
20742109
def update_agentpool_profile_preview(self, agentpools: List[AgentPool] = None) -> AgentPool:
20752110
"""The overall controller used to update the preview AgentPool profile.
20762111
@@ -2139,6 +2174,9 @@ def update_agentpool_profile_preview(self, agentpools: List[AgentPool] = None) -
21392174
# update crg id
21402175
agentpool = self.update_crg(agentpool)
21412176

2177+
# update prepared image specification
2178+
agentpool = self.update_prepared_image_specification(agentpool)
2179+
21422180
return agentpool
21432181

21442182
def update_auto_scaler_properties(self, agentpool: AgentPool) -> AgentPool:

0 commit comments

Comments
 (0)