Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* `az aks create`: Honor `--enable-osdisk-full-caching` for the default agent pool.
* `az aks kollect` and `az aks kanalyze`: Fix compatibility with the keyword-only credential SDK parameters.
* `az aks maintenanceconfiguration add` and `az aks maintenanceconfiguration update`: Preserve configuration-file fields with the typespec-generated SDK model.
* Improve AKS live-test resilience for preview feature gates, transient resource and monitoring-table readiness, retired configurations, and service propagation delays.

22.0.0b1
++++++++
Expand Down
2 changes: 1 addition & 1 deletion src/aks-preview/azext_aks_preview/aks_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def _get_temp_kubeconfig_path(cmd, client, resource_group_name: str, name: str,
_, temp_kubeconfig_path = tempfile.mkstemp()

# Use normal user credentials, not admin credentials (admin creds will not be supplied if local accounts are disabled).
credentialResults = client.list_cluster_user_credentials(resource_group_name, name, None)
credentialResults = client.list_cluster_user_credentials(resource_group_name, name, server_fqdn=None)
kubeconfig = credentialResults.kubeconfigs[0].value.decode(encoding='UTF-8')
print_or_merge_credentials(temp_kubeconfig_path, kubeconfig, False, None)

Expand Down
61 changes: 41 additions & 20 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,41 @@ def _ssl_context():
return ssl.create_default_context()


# The Log Analytics workspace's default output tables (e.g. the ContainerInsights solution
# tables) can take a short while to finish provisioning right after the workspace itself, or
# its association with the ContainerInsights solution, reports "Succeeded". During that window
# a Data Collection Rule (DCR) PUT referencing those tables can fail synchronously with
# "InvalidOutputTable" even though the workspace is otherwise ready.
_DCR_TABLE_READINESS_MAX_RETRY_TIMES = 5
_DCR_TABLE_READINESS_RETRY_DELAY_SECONDS = 15


def _create_or_update_dcr_with_table_readiness_retry(resources, dcr_resource_id, api_version, body):
"""
Create/update a Data Collection Rule (DCR), applying a bounded backoff-and-retry
specifically for the known-transient "InvalidOutputTable" readiness error described above.
Any other error keeps the pre-existing immediate-retry policy (up to 3 attempts, no delay)
and is re-raised unchanged once that bound is exhausted.
"""
_MAX_RETRY_TIMES = 3
error = None
readiness_retries = 0
attempt = 0
while True:
try:
resources.begin_create_or_update_by_id(dcr_resource_id, api_version, body)
return
except (CLIError, HttpResponseError) as e:
error = e
if "InvalidOutputTable" in str(e) and readiness_retries < _DCR_TABLE_READINESS_MAX_RETRY_TIMES:
readiness_retries += 1
time.sleep(_DCR_TABLE_READINESS_RETRY_DELAY_SECONDS)
continue
attempt += 1
if attempt >= _MAX_RETRY_TIMES:
raise error


# pylint: disable=too-many-locals,too-many-branches,too-many-statements,line-too-long
def ensure_container_insights_for_monitoring_preview(
cmd,
Expand Down Expand Up @@ -581,26 +616,12 @@ def __init__(self, location, resource_id):
)

resources = get_resources_client(cmd.cli_ctx, cluster_subscription)
for _ in range(3):
try:
if enable_syslog:
resources.begin_create_or_update_by_id(
dcr_resource_id,
"2022-06-01",
json.loads(dcr_creation_body_with_syslog)
)
else:
resources.begin_create_or_update_by_id(
dcr_resource_id,
"2022-06-01",
json.loads(dcr_creation_body_without_syslog)
)
error = None
break
except (CLIError, HttpResponseError) as e:
error = e
else:
raise error
_create_or_update_dcr_with_table_readiness_retry(
resources,
dcr_resource_id,
"2022-06-01",
json.loads(dcr_creation_body_with_syslog) if enable_syslog else json.loads(dcr_creation_body_without_syslog),
)

if create_dcra:
# only create or delete the association between the DCR and cluster
Expand Down
12 changes: 11 additions & 1 deletion src/aks-preview/azext_aks_preview/maintenanceconfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ def getMaintenanceConfiguration(cmd, raw_parameters):
if config_file is not None:
mcr = get_file_json(config_file)
logger.info(mcr)
return mcr
# The config file is authored in the flattened display shape (e.g. a top-level
# "maintenanceWindow" key, matching what `aks maintenanceconfiguration show` prints),
# but the generated SDK model requires the ARM wire shape with fields nested under
# "properties". Without this wrapping, the PUT body silently drops the flattened
# fields and the service rejects/ignores them.
MaintenanceConfiguration = cmd.get_models(
"MaintenanceConfiguration",
resource_type=CUSTOM_MGMT_AKS_PREVIEW,
operation_group="maintenance_configurations"
)
return MaintenanceConfiguration({"properties": mcr})

if maintenance_window_id is not None:
return constructSharedMaintenanceConfiguration(cmd, raw_parameters)
Expand Down
20 changes: 20 additions & 0 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,12 @@ def _get_enable_fips_from_mc(self) -> Optional[bool]:
return properties.get("enableFIPS")
return None

def get_enable_os_disk_full_caching(self) -> bool:
"""Obtain the value of enable_os_disk_full_caching for the default agent pool profile.
:return: bool
"""
return self.raw_param.get("enable_os_disk_full_caching")

def get_enable_fips(self) -> bool:
"""Obtain the value of enable_fips.
:return: bool
Expand Down Expand Up @@ -4767,6 +4773,18 @@ def set_up_enable_fips(self, mc: ManagedCluster) -> ManagedCluster:
agentpool.enable_fips = True
return mc

def set_up_os_disk_full_caching(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up enable_os_disk_full_caching for the default agent pool profile.

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

if self.context.get_enable_os_disk_full_caching():
if mc.agent_pool_profiles:
mc.agent_pool_profiles[0].enable_os_disk_full_caching = True
return mc

def set_up_service_account_image_pull(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up security profile serviceAccountImagePullProfile for the ManagedCluster object.

Expand Down Expand Up @@ -5822,6 +5840,8 @@ def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) ->
mc = self.set_up_image_integrity(mc)
# set up FIPS mode at the cluster level
mc = self.set_up_enable_fips(mc)
# set up full-cache ephemeral OS disk on the default agent pool profile
mc = self.set_up_os_disk_full_caching(mc)
# set up service account image pull
mc = self.set_up_service_account_image_pull(mc)
# set up KMS infrastructure encryption
Expand Down
Loading
Loading