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

Add enable ASM egress gateway commands for az aks mesh #6768

Merged
merged 20 commits into from
Sep 19, 2023
22 changes: 22 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,28 @@
text: az aks mesh disable-ingress-gateway --resource-group MyResourceGroup --name MyManagedCluster --ingress-gateway-type Internal
"""

helps['aks mesh enable-egress-gateway'] = """
type: command
short-summary: Enable an Azure Service Mesh egress gateway.
long-summary: This command enables an Azure Service Mesh egress gateway in given cluster.
parameters:
- name: --egress-gateway-nodeselector --egx-gtw-ns
type: string
short-summary: Specify the node selector for the egress gateway with space-separated, key-value pairs (key1=value1 key2=value2).
examples:
- name: Enable an egress gateway.
text: az aks mesh enable-egress-gateway --resource-group MyResourceGroup --name MyManagedCluster --egress-gateway-nodeselector istio=egress
"""

helps['aks mesh disable-egress-gateway'] = """
type: command
short-summary: Disable an Azure Service Mesh egress gateway.
long-summary: This command disables an Azure Service Mesh egress gateway in given cluster.
examples:
- name: Disable an egress gateway.
text: az aks mesh disable-egress-gateway --resource-group MyResourceGroup --name MyManagedCluster
"""

helps['aks copilot'] = """
type: command
short-summary: Start a chat with the Azure Kubernetes Service expert. API keys for OpenAI or Azure are required.
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 @@ -118,6 +118,7 @@
validate_defender_config_parameter,
validate_defender_disable_and_enable_parameters,
validate_disable_windows_outbound_nat,
validate_egress_gtw_nodeselector,
validate_enable_custom_ca_trust,
validate_eviction_policy,
validate_grafanaresourceid,
Expand Down Expand Up @@ -918,6 +919,10 @@ def load_arguments(self, _):
c.argument('ingress_gateway_type',
arg_type=get_enum_type(ingress_gateway_types))

with self.argument_context('aks mesh enable-egress-gateway') as c:
c.argument('egx_gtw_nodeselector', nargs='*', validator=validate_egress_gtw_nodeselector, required=False, default=None,
options_list=["--egress-gateway-nodeselector", "--egx-gtw-ns"])

with self.argument_context('aks mesh enable') as c:
c.argument('key_vault_id')
c.argument('ca_cert_object_name')
Expand Down
24 changes: 24 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,30 @@ def validate_node_public_ip_tags(ns):
ns.node_public_ip_tags = tags_dict


def validate_egress_gtw_nodeselector(namespace):
"""Validates that provided node selector is a valid format"""

if not hasattr(namespace, 'egx_gtw_nodeselector'):
return

labels = namespace.egx_gtw_nodeselector

if labels is None:
# no specify any labels
namespace.egx_gtw_nodeselector = {}
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)

namespace.egx_gtw_nodeselector = after_validation_labels


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

Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,17 @@ def load_command_table(self, _):
'enable-ingress-gateway',
'aks_mesh_enable_ingress_gateway',
supports_no_wait=True)
g.custom_command(
'enable-egress-gateway',
'aks_mesh_enable_egress_gateway',
supports_no_wait=True)
g.custom_command(
'disable-ingress-gateway',
'aks_mesh_disable_ingress_gateway',
supports_no_wait=True,
confirmation=True)
g.custom_command(
'disable-egress-gateway',
'aks_mesh_disable_egress_gateway',
supports_no_wait=True,
confirmation=True)
36 changes: 36 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2491,6 +2491,39 @@ def aks_mesh_disable_ingress_gateway(
ingress_gateway_type=ingress_gateway_type)


def aks_mesh_enable_egress_gateway(
cmd,
client,
resource_group_name,
name,
egx_gtw_nodeselector,
):
return _aks_mesh_update(
cmd,
client,
resource_group_name,
name,
enable_azure_service_mesh=True,
enable_egress_gateway=True,
egx_gtw_nodeselector=egx_gtw_nodeselector)


def aks_mesh_disable_egress_gateway(
cmd,
client,
resource_group_name,
name,
):
return _aks_mesh_update(
cmd,
client,
resource_group_name,
name,
enable_azure_service_mesh=True,
disable_egress_gateway=True,
egx_gtw_nodeselector=None)


def _aks_mesh_update(
cmd,
client,
Expand All @@ -2506,6 +2539,9 @@ def _aks_mesh_update(
enable_ingress_gateway=None,
disable_ingress_gateway=None,
ingress_gateway_type=None,
enable_egress_gateway=None,
egx_gtw_nodeselector=None,
disable_egress_gateway=None,
):
raw_parameters = locals()

Expand Down
69 changes: 62 additions & 7 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2112,14 +2112,18 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile:
disable_ingress_gateway = self.raw_param.get("disable_ingress_gateway", False)
ingress_gateway_type = self.raw_param.get("ingress_gateway_type", None)

enable_egress_gateway = self.raw_param.get("enable_egress_gateway", False)
disable_egress_gateway = self.raw_param.get("disable_egress_gateway", False)
egx_gtw_nodeselector = self.raw_param.get("egx_gtw_nodeselector", None)

if enable_ingress_gateway and disable_ingress_gateway:
raise MutuallyExclusiveArgumentError(
"Cannot both enable and disable azure service mesh ingress gateway at the same time.",
)

# deal with gateways
# deal with ingress gateways
if enable_ingress_gateway or disable_ingress_gateway:
# if a gateway is enabled, enable the mesh
# if an ingress gateway is enabled, enable the mesh
if enable_ingress_gateway:
new_profile.mode = CONST_AZURE_SERVICE_MESH_MODE_ISTIO
updated = True
Expand All @@ -2135,17 +2139,17 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile:
new_profile.istio.components.ingress_gateways = []
updated = True

# make update if the gateway already exist
gateway_exists = False
# make update if the ingress gateway already exist
ingress_gateway_exists = False
for ingress in new_profile.istio.components.ingress_gateways:
if ingress.mode == ingress_gateway_type:
ingress.enabled = enable_ingress_gateway
gateway_exists = True
ingress_gateway_exists = True
updated = True
break

# gateway not exist, append
if not gateway_exists:
# ingress gateway not exist, append
if not ingress_gateway_exists:
new_profile.istio.components.ingress_gateways.append(
self.models.IstioIngressGateway(
mode=ingress_gateway_type,
Expand All @@ -2154,6 +2158,57 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile:
)
updated = True

# deal with egress gateways
if enable_egress_gateway and disable_egress_gateway:
raise MutuallyExclusiveArgumentError(
"Cannot both enable and disable azure service mesh egress gateway at the same time.",
)

if not enable_egress_gateway and egx_gtw_nodeselector:
raise MutuallyExclusiveArgumentError(
"Cannot set egress gateway nodeselector without enabling an egress gateway.",
)

if enable_egress_gateway or disable_egress_gateway:
# if a gateway is enabled, enable the mesh
if enable_egress_gateway:
new_profile.mode = CONST_AZURE_SERVICE_MESH_MODE_ISTIO
updated = True

# ensure necessary fields
if new_profile.istio.components is None:
new_profile.istio.components = self.models.IstioComponents()
updated = True
if new_profile.istio.components.egress_gateways is None:
new_profile.istio.components.egress_gateways = []
updated = True

# make update if the egress gateway already exists
egress_gateway_exists = False
for egress in new_profile.istio.components.egress_gateways:
egress.enabled = enable_egress_gateway
egress.node_selector = egx_gtw_nodeselector
egress_gateway_exists = True
updated = True
break

# egress gateway doesn't exist, append
if not egress_gateway_exists:
if egx_gtw_nodeselector:
new_profile.istio.components.egress_gateways.append(
self.models.IstioEgressGateway(
enabled=enable_egress_gateway,
node_selector=egx_gtw_nodeselector,
)
)
else:
new_profile.istio.components.egress_gateways.append(
self.models.IstioEgressGateway(
enabled=enable_egress_gateway,
)
)
updated = True

# deal with plugin ca
key_vault_id = self.raw_param.get("key_vault_id", None)
ca_cert_object_name = self.raw_param.get("ca_cert_object_name", None)
Expand Down
Loading