Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aks-preview: feature support for apiserver vnet integration #4787

Merged
merged 2 commits into from
May 12, 2022
Merged
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
6 changes: 4 additions & 2 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* Update to use 2022-04-02-preview api version.

0.5.67 (NOT RELEASED)

0.5.67
+++++++++++++++++++++
* Add support for csi drivers extensibility.
* Update to use 2022-04-02-preview api version.
* Add support for apiserver vnet integration.

0.5.66
++++++
Expand Down
12 changes: 12 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@
- name: --attach-acr
type: string
short-summary: Grant the 'acrpull' role assignment to the ACR specified by name or resource ID.
- name: --enable-apiserver-vnet-integration
type: bool
short-summary: Enable integration of user vnet with control plane apiserver pods.
- name: --apiserver-subnet-id
type: string
short-summary: The ID of a subnet in an existing VNet into which to assign control plane apiserver pods(requires --enable-apiserver-vnet-integration)
- name: --enable-private-cluster
type: string
short-summary: Enable private cluster.
Expand Down Expand Up @@ -737,6 +743,12 @@
- name: --azure-keyvault-kms-key-id
type: string
short-summary: Identifier of Azure Key Vault key.
- name: --enable-apiserver-vnet-integration
type: bool
short-summary: Enable integration of user vnet with control plane apiserver pods.
- name: --apiserver-subnet-id
type: string
short-summary: The ID of a subnet in an existing VNet into which to assign control plane apiserver pods(requires --enable-apiserver-vnet-integration)
examples:
- name: Reconcile the cluster back to its current state.
text: az aks update -g MyResourceGroup -n MyManagedCluster
Expand Down
5 changes: 5 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
validate_acr,
validate_addon,
validate_addons,
validate_apiserver_subnet_id,
validate_assign_identity,
validate_assign_kubelet_identity,
validate_azure_keyvault_kms_key_id,
Expand Down Expand Up @@ -293,6 +294,8 @@ def load_arguments(self, _):
c.argument('message_of_the_day')
c.argument('gpu_instance_profile', arg_type=get_enum_type(gpu_instance_profiles))
c.argument('workload_runtime', arg_type=get_enum_type(workload_runtimes), default=CONST_WORKLOAD_RUNTIME_OCI_CONTAINER)
c.argument('enable_apiserver_vnet_integration', action='store_true', is_preview=True)
c.argument('apiserver_subnet_id', validator=validate_apiserver_subnet_id, is_preview=True)

with self.argument_context('aks update') as c:
# managed cluster paramerters
Expand Down Expand Up @@ -365,6 +368,8 @@ def load_arguments(self, _):
c.argument('enable_oidc_issuer', action='store_true', is_preview=True)
c.argument('enable_azure_keyvault_kms', action='store_true', is_preview=True)
c.argument('azure_keyvault_kms_key_id', validator=validate_azure_keyvault_kms_key_id, is_preview=True)
c.argument('enable_apiserver_vnet_integration', action='store_true', is_preview=True)
c.argument('apiserver_subnet_id', validator=validate_apiserver_subnet_id, is_preview=True)

with self.argument_context('aks scale') as c:
c.argument('nodepool_name',
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ def validate_pod_subnet_id(namespace):
_validate_subnet_id(namespace.pod_subnet_id, "--pod-subnet-id")


def validate_apiserver_subnet_id(namespace):
_validate_subnet_id(namespace.apiserver_subnet_id, "--apiserver-subnet-id")


def _validate_subnet_id(subnet_id, name):
if subnet_id is None or subnet_id == '':
return
Expand Down
6 changes: 5 additions & 1 deletion src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,8 @@ def aks_create(cmd,
message_of_the_day=None,
enable_azure_keyvault_kms=False,
azure_keyvault_kms_key_id=None,
enable_apiserver_vnet_integration=False,
apiserver_subnet_id=None,
yes=False):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -890,7 +892,9 @@ def aks_update(cmd, # pylint: disable=too-many-statements,too-many-branches,
enable_oidc_issuer=False,
http_proxy_config=None,
enable_azure_keyvault_kms=False,
azure_keyvault_kms_key_id=None):
azure_keyvault_kms_key_id=None,
enable_apiserver_vnet_integration=False,
apiserver_subnet_id=None):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()

Expand Down
138 changes: 138 additions & 0 deletions src/aks-preview/azext_aks_preview/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
ManagedClusterStorageProfileDiskCSIDriver = TypeVar('ManagedClusterStorageProfileDiskCSIDriver')
ManagedClusterStorageProfileFileCSIDriver = TypeVar('ManagedClusterStorageProfileFileCSIDriver')
ManagedClusterStorageProfileSnapshotController = TypeVar('ManagedClusterStorageProfileSnapshotController')
ManagedClusterAPIServerAccessProfile = TypeVar('ManagedClusterAPIServerAccessProfile')
Snapshot = TypeVar("Snapshot")
ManagedClusterSnapshot = TypeVar("ManagedClusterSnapshot")
AzureKeyVaultKms = TypeVar('AzureKeyVaultKms')
Expand Down Expand Up @@ -166,6 +167,11 @@ def __init__(self, cmd: AzCommandsLoader, resource_type: ResourceType):
resource_type=self.resource_type,
operation_group="managed_clusters",
)
self.ManagedClusterAPIServerAccessProfile = self.__cmd.get_models(
"ManagedClusterAPIServerAccessProfile",
resource_type=self.resource_type,
operation_group="managed_clusters",
)
# holder for nat gateway related models
self.__nat_gateway_models = None
# holder for pod identity related models
Expand Down Expand Up @@ -1964,6 +1970,110 @@ def get_cluster_uaidentity_object_id(self) -> str:
cluster_identity_resource_id = assigned_identity
return self.get_identity_by_msi_client(cluster_identity_resource_id).principal_id

def _get_enable_apiserver_vnet_integration(self, enable_validation: bool = False) -> bool:
"""Internal function to obtain the value of enable_apiserver_vnet_integration.

This function supports the option of enable_validation. When enable_apiserver_vnet_integration is specified,
For CREATE: if enable-private-cluster is not used, raise an RequiredArgumentMissingError;
For UPDATE: if apiserver-subnet-id is not used, raise an RequiredArgumentMissingError;

:return: bool
"""
# read the original value passed by the command
enable_apiserver_vnet_integration = self.raw_param.get("enable_apiserver_vnet_integration")
# In create mode, try to read the property value corresponding to the parameter from the `mc` object.
if self.decorator_mode == DecoratorMode.CREATE:
if (
self.mc and
self.mc.api_server_access_profile and
self.mc.api_server_access_profile.enable_vnet_integration is not None
):
enable_apiserver_vnet_integration = self.mc.api_server_access_profile.enable_vnet_integration

# this parameter does not need dynamic completion
# validation
if enable_validation:
if self.decorator_mode == DecoratorMode.CREATE:
if enable_apiserver_vnet_integration:
# remove this validation after we support public cluster
if not self._get_enable_private_cluster(enable_validation=False):
raise RequiredArgumentMissingError(
"--apiserver-vnet-integration is only supported for private cluster right now. "
"Please use it together with --enable-private-cluster"
)
if self.decorator_mode == DecoratorMode.UPDATE:
if enable_apiserver_vnet_integration:
Copy link
Member

Choose a reason for hiding this comment

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

do we need to validate if it is private cluster or not?
It is validated by rp right now, which means that is only nice to have. asking is because I see it in CREATE path but missed in UPDATE path.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for the update, I don't think we need to pass the parameter --enable-private-cluster. And cli side cannot get existing mc so we cannot tell if it's private cluster or not at cli side.

Copy link
Member

Choose a reason for hiding this comment

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

ok, that make sense.

Copy link
Member

@FumingZhang FumingZhang May 11, 2022

Choose a reason for hiding this comment

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

Actually, you could check if this is a private cluster with a helper function check_is_private_cluster (azure.cli.command_modules.acs._helpers.check_is_private_cluster). In an update scenario, the mc in the context is the "existing mc".

More details about "existing mc". To be honest, the current decorator does not record the original mc obtained by a GET at the beginning of the update command. The mc in the context is gradually updated with the update of each sub-profile, but I think it is impossible to modify whether a cluster is a private cluster through update? So you can use this "existing mc" to check directly.

The original mc will be preserved in the upcoming v2 decorator.

if self._get_apiserver_subnet_id(enable_validation=False) is None:
raise RequiredArgumentMissingError(
"--apiserver-subnet-id is required for update with --apiserver-vnet-integration."
)

return enable_apiserver_vnet_integration

def get_enable_apiserver_vnet_integration(self) -> bool:
"""Obtain the value of enable_apiserver_vnet_integration.

This function will verify the parameter by default. When enable_apiserver_vnet_integration is specified,
For CREATE: if enable-private-cluster is not used, raise an RequiredArgumentMissingError;
For UPDATE: if apiserver-subnet-id is not used, raise an RequiredArgumentMissingError

:return: bool
"""
return self._get_enable_apiserver_vnet_integration(enable_validation=True)

def _get_apiserver_subnet_id(self, enable_validation: bool = False) -> Union[str, None]:
"""Internal function to obtain the value of apiserver_subnet_id.

This function supports the option of enable_validation. When apiserver_subnet_id is specified,
if enable_apiserver_vnet_integration is not used, raise an RequiredArgumentMissingError;
For CREATE: if vnet_subnet_id is not used, raise an RequiredArgumentMissingError;

:return: bool
"""
# read the original value passed by the command
apiserver_subnet_id = self.raw_param.get("apiserver_subnet_id")
# try to read the property value corresponding to the parameter from the `mc` object
if self.decorator_mode == DecoratorMode.CREATE:
if (
self.mc and
self.mc.api_server_access_profile and
self.mc.api_server_access_profile.subnet_id is not None
):
apiserver_subnet_id = self.mc.api_server_access_profile.subnet_id

# this parameter does not need dynamic completion
# validation
if enable_validation:
if self.decorator_mode == DecoratorMode.CREATE:
vnet_subnet_id = self.get_vnet_subnet_id()
if apiserver_subnet_id and vnet_subnet_id is None:
raise RequiredArgumentMissingError(
'"--apiserver-subnet-id" requires "--vnet-subnet-id".')

enable_apiserver_vnet_integration = self._get_enable_apiserver_vnet_integration(
enable_validation=False)
if (
apiserver_subnet_id and
(
enable_apiserver_vnet_integration is None or
enable_apiserver_vnet_integration is False
)
):
raise RequiredArgumentMissingError(
'"--apiserver-subnet-id" requires "--enable-apiserver-vnet-integration".')

return apiserver_subnet_id

def get_apiserver_subnet_id(self) -> Union[str, None]:
"""Obtain the value of apiserver_subnet_id.

This function will verify the parameter by default. When apiserver_subnet_id is specified,
if enable_apiserver_vnet_integration is not specified, raise an RequiredArgumentMissingError;

:return: bool
"""
return self._get_apiserver_subnet_id(enable_validation=True)


class AKSPreviewCreateDecorator(AKSCreateDecorator):
# pylint: disable=super-init-not-called
Expand Down Expand Up @@ -2346,6 +2456,19 @@ def set_up_azure_keyvault_kms(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def set_up_api_server_access_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up apiserverAccessProfile enableVnetIntegration and subnetId for the ManagedCluster object.

:return: the ManagedCluster object
"""
mc = super().set_up_api_server_access_profile(mc)
if self.context.get_enable_apiserver_vnet_integration():
mc.api_server_access_profile.enable_vnet_integration = True
if self.context.get_apiserver_subnet_id():
mc.api_server_access_profile.subnet_id = self.context.get_apiserver_subnet_id()

return mc

def construct_mc_preview_profile(self) -> ManagedCluster:
"""The overall controller used to construct the preview ManagedCluster profile.

Expand Down Expand Up @@ -2752,6 +2875,21 @@ def update_identity_profile(self, mc: ManagedCluster) -> ManagedCluster:
mc.identity_profile = identity_profile
return mc

def update_api_server_access_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Update apiServerAccessProfile vnet integration related property for the ManagedCluster object.

:return: the ManagedCluster object
"""
mc = super().update_api_server_access_profile(mc)
if self.context.get_enable_apiserver_vnet_integration():
if mc.api_server_access_profile is None:
mc.api_server_access_profile = self.models.ManagedClusterAPIServerAccessProfile()
mc.api_server_access_profile.enable_vnet_integration = True
if self.context.get_apiserver_subnet_id():
mc.api_server_access_profile.subnet_id = self.context.get_apiserver_subnet_id()

levimm marked this conversation as resolved.
Show resolved Hide resolved
return mc

def patch_mc(self, mc: ManagedCluster) -> ManagedCluster:
"""Helper function to patch the ManagedCluster object.

Expand Down
Loading