Skip to content
Merged
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