Skip to content

Commit c56e257

Browse files
authored
[AKS] az aks mesh enable-egress-gateway: Add istio egress CLI commands (#32386)
1 parent ce7ffa1 commit c56e257

File tree

9 files changed

+586
-7
lines changed

9 files changed

+586
-7
lines changed

src/azure-cli/azure/cli/command_modules/acs/_consts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@
244244
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START = "Start"
245245
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE = "Complete"
246246
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK = "Rollback"
247+
CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE = "aks-istio-egress"
248+
CONST_AZURE_SERVICE_MESH_MAX_EGRESS_NAME_LENGTH = 63
247249

248250
# Dns zone contributor role
249251
CONST_PRIVATE_DNS_ZONE_CONTRIBUTOR_ROLE = "Private DNS Zone Contributor"

src/azure-cli/azure/cli/command_modules/acs/_help.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2729,6 +2729,46 @@
27292729
text: az aks mesh disable-ingress-gateway --resource-group MyResourceGroup --name MyManagedCluster --ingress-gateway-type Internal
27302730
"""
27312731

2732+
helps['aks mesh enable-egress-gateway'] = """
2733+
type: command
2734+
short-summary: Enable an Azure Service Mesh egress gateway.
2735+
long-summary: This command enables an Azure Service Mesh egress gateway in given cluster.
2736+
parameters:
2737+
- name: --istio-eg-gtw-name --istio-egressgateway-name
2738+
type: string
2739+
short-summary: Specify the name of the Istio egress gateway.
2740+
long-summary: This required field specifies the name of the Istio egress gateway. Must be between 1 and 253 characters, must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character.
2741+
- name: --istio-eg-gtw-ns --istio-egressgateway-namespace
2742+
type: string
2743+
short-summary: Specify the namespace of the Istio egress gateway.
2744+
long-summary: This optional field specifies the namespace of the Istio egress gateway. Defaults to "aks-istio-egress" if unspecified.
2745+
- name: --gateway-configuration-name --gtw-config-name
2746+
type: string
2747+
short-summary: Specify the name of the StaticGatewayConfiguration resource.
2748+
long-summary: This required field specifies the name of the StaticGatewayConfiguration resource for the Istio egress gateway. See https://aka.ms/aks-static-egress-gateway on how to create and configure a Static Egress Gateway agentpool.
2749+
examples:
2750+
- name: Enable an Istio egress gateway. Static egress gateway must be enabled prior to creating an Istio egress gateway. See https://aka.ms/aks-static-egress-gateway on how to create and configure a Static Egress Gateway agentpool.
2751+
text: az aks mesh enable-egress-gateway --resource-group MyResourceGroup --name MyManagedCluster --istio-egressgateway-name my-istio-egress-1 --istio-egressgateway-namespace my-namespace-1 --gateway-configuration-name sgc-istio-egress-1
2752+
"""
2753+
2754+
helps['aks mesh disable-egress-gateway'] = """
2755+
type: command
2756+
short-summary: Disable an Azure Service Mesh egress gateway.
2757+
long-summary: This command disables an Azure Service Mesh egress gateway in given cluster.
2758+
parameters:
2759+
- name: --istio-eg-gtw-name --istio-egressgateway-name
2760+
type: string
2761+
short-summary: Specify the name of the Istio egress gateway.
2762+
long-summary: This required field specifies the name of the Istio egress gateway. Must be between 1 and 253 characters, must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character.
2763+
- name: --istio-eg-gtw-ns --istio-egressgateway-namespace
2764+
type: string
2765+
short-summary: Specify the namespace of the Istio egress gateway.
2766+
long-summary: This optional field specifies the namespace of the Istio egress gateway. Defaults to "aks-istio-egress" if unspecified.
2767+
examples:
2768+
- name: Disable an Istio egress gateway.
2769+
text: az aks mesh disable-egress-gateway --resource-group MyResourceGroup --name MyManagedCluster --istio-egressgateway-name my-istio-egress-1 --istio-egressgateway-namespace my-namespace-1
2770+
"""
2771+
27322772
helps["aks mesh get-revisions"] = """
27332773
type: command
27342774
short-summary: Discover available Azure Service Mesh revisions and their compatibility.

src/azure-cli/azure/cli/command_modules/acs/_params.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP_CONFIGURATION,
6363
CONST_AZURE_SERVICE_MESH_INGRESS_MODE_EXTERNAL,
6464
CONST_AZURE_SERVICE_MESH_INGRESS_MODE_INTERNAL,
65+
CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE,
6566
CONST_NRG_LOCKDOWN_RESTRICTION_LEVEL_READONLY,
6667
CONST_NRG_LOCKDOWN_RESTRICTION_LEVEL_UNRESTRICTED,
6768
CONST_ARTIFACT_SOURCE_DIRECT,
@@ -126,6 +127,7 @@
126127
validate_allowed_host_ports, validate_application_security_groups,
127128
validate_node_public_ip_tags,
128129
validate_disable_windows_outbound_nat,
130+
validate_asm_egress_name,
129131
validate_crg_id, validate_apiserver_subnet_id,
130132
validate_azure_service_mesh_revision,
131133
validate_message_of_the_day,
@@ -1168,6 +1170,39 @@ def load_arguments(self, _):
11681170
c.argument('ingress_gateway_type',
11691171
arg_type=get_enum_type(ingress_gateway_types))
11701172

1173+
with self.argument_context("aks mesh enable-egress-gateway") as c:
1174+
c.argument(
1175+
"istio_egressgateway_name",
1176+
validator=validate_asm_egress_name,
1177+
required=True,
1178+
options_list=["--istio-egressgateway-name", "--istio-eg-gtw-name"]
1179+
)
1180+
c.argument(
1181+
"istio_egressgateway_namespace",
1182+
required=False,
1183+
default=CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE,
1184+
options_list=["--istio-egressgateway-namespace", "--istio-eg-gtw-ns"]
1185+
)
1186+
c.argument(
1187+
"gateway_configuration_name",
1188+
required=True,
1189+
options_list=["--gateway-configuration-name", "--gtw-config-name"]
1190+
)
1191+
1192+
with self.argument_context("aks mesh disable-egress-gateway") as c:
1193+
c.argument(
1194+
"istio_egressgateway_name",
1195+
validator=validate_asm_egress_name,
1196+
required=True,
1197+
options_list=["--istio-egressgateway-name", "--istio-eg-gtw-name"]
1198+
)
1199+
c.argument(
1200+
"istio_egressgateway_namespace",
1201+
required=False,
1202+
default=CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE,
1203+
options_list=["--istio-egressgateway-namespace", "--istio-eg-gtw-ns"]
1204+
)
1205+
11711206
with self.argument_context('aks mesh enable') as c:
11721207
c.argument('revision', validator=validate_azure_service_mesh_revision)
11731208
c.argument('key_vault_id')

src/azure-cli/azure/cli/command_modules/acs/_validators.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
CONST_NETWORK_POD_IP_ALLOCATION_MODE_DYNAMIC_INDIVIDUAL,
2020
CONST_NETWORK_POD_IP_ALLOCATION_MODE_STATIC_BLOCK,
2121
CONST_NODEPOOL_MODE_GATEWAY,
22+
CONST_AZURE_SERVICE_MESH_MAX_EGRESS_NAME_LENGTH,
2223
CONST_VIRTUAL_MACHINE_SCALE_SETS,
2324
CONST_AVAILABILITY_SET,
2425
CONST_VIRTUAL_MACHINES,
@@ -183,6 +184,20 @@ def validate_agent_pool_name(namespace):
183184
_validate_nodepool_name(namespace.agent_pool_name)
184185

185186

187+
def validate_asm_egress_name(namespace):
188+
if namespace.istio_egressgateway_name is None:
189+
return
190+
name = namespace.istio_egressgateway_name
191+
asm_egress_name_regex = re.compile(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$')
192+
match = asm_egress_name_regex.match(name)
193+
if not match or len(name) > CONST_AZURE_SERVICE_MESH_MAX_EGRESS_NAME_LENGTH:
194+
raise InvalidArgumentValueError(
195+
f"Istio egress name {name} is invalid. Name must be between 1 and "
196+
f"{CONST_AZURE_SERVICE_MESH_MAX_EGRESS_NAME_LENGTH} characters, must consist of lower case alphanumeric "
197+
"characters, '-' or '.', and must start and end with an alphanumeric character."
198+
)
199+
200+
186201
def validate_kubectl_version(namespace):
187202
"""Validates a string as a possible Kubernetes version."""
188203
k8s_release_regex = re.compile(r'^[v|V]?(\d+\.\d+\.\d+.*|latest)$')

src/azure-cli/azure/cli/command_modules/acs/commands.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,20 @@ def load_command_table(self, _):
277277
'enable-ingress-gateway',
278278
'aks_mesh_enable_ingress_gateway',
279279
supports_no_wait=True)
280+
g.custom_command(
281+
"enable-egress-gateway",
282+
"aks_mesh_enable_egress_gateway",
283+
supports_no_wait=True)
280284
g.custom_command(
281285
'disable-ingress-gateway',
282286
'aks_mesh_disable_ingress_gateway',
283287
supports_no_wait=True,
284288
confirmation=True)
289+
g.custom_command(
290+
"disable-egress-gateway",
291+
"aks_mesh_disable_egress_gateway",
292+
supports_no_wait=True,
293+
confirmation=True)
285294
g.custom_command(
286295
'get-revisions',
287296
'aks_mesh_get_revisions',

src/azure-cli/azure/cli/command_modules/acs/custom.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3598,6 +3598,44 @@ def aks_mesh_disable_ingress_gateway(
35983598
ingress_gateway_type=ingress_gateway_type)
35993599

36003600

3601+
def aks_mesh_enable_egress_gateway(
3602+
cmd,
3603+
client,
3604+
resource_group_name,
3605+
name,
3606+
istio_egressgateway_name,
3607+
istio_egressgateway_namespace,
3608+
gateway_configuration_name,
3609+
):
3610+
return _aks_mesh_update(
3611+
cmd,
3612+
client,
3613+
resource_group_name,
3614+
name,
3615+
enable_egress_gateway=True,
3616+
istio_egressgateway_name=istio_egressgateway_name,
3617+
istio_egressgateway_namespace=istio_egressgateway_namespace,
3618+
gateway_configuration_name=gateway_configuration_name)
3619+
3620+
3621+
def aks_mesh_disable_egress_gateway(
3622+
cmd,
3623+
client,
3624+
resource_group_name,
3625+
name,
3626+
istio_egressgateway_name,
3627+
istio_egressgateway_namespace,
3628+
):
3629+
return _aks_mesh_update(
3630+
cmd,
3631+
client,
3632+
resource_group_name,
3633+
name,
3634+
istio_egressgateway_name=istio_egressgateway_name,
3635+
istio_egressgateway_namespace=istio_egressgateway_namespace,
3636+
disable_egress_gateway=True)
3637+
3638+
36013639
def aks_mesh_get_revisions(
36023640
cmd,
36033641
client,
@@ -3720,6 +3758,11 @@ def _aks_mesh_update(
37203758
enable_ingress_gateway=None,
37213759
disable_ingress_gateway=None,
37223760
ingress_gateway_type=None,
3761+
enable_egress_gateway=None,
3762+
disable_egress_gateway=None,
3763+
istio_egressgateway_name=None,
3764+
istio_egressgateway_namespace=None,
3765+
gateway_configuration_name=None,
37233766
revision=None,
37243767
yes=False,
37253768
mesh_upgrade_command=None,

src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START,
4242
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE,
4343
CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK,
44+
CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE,
4445
CONST_PRIVATE_DNS_ZONE_CONTRIBUTOR_ROLE,
4546
CONST_DNS_ZONE_CONTRIBUTOR_ROLE,
4647
CONST_ARTIFACT_SOURCE_CACHE,
@@ -4658,7 +4659,7 @@ def _handle_ingress_gateways_asm(self, new_profile: ServiceMeshProfile) -> Tuple
46584659
disable_ingress_gateway = self.raw_param.get("disable_ingress_gateway", False)
46594660
ingress_gateway_type = self.raw_param.get("ingress_gateway_type", None)
46604661

4661-
# disallow disable ingress gateway on a cluser with no asm enabled
4662+
# disallow disable ingress gateway on a cluster with no asm enabled
46624663
if disable_ingress_gateway:
46634664
if new_profile is None or new_profile.mode == CONST_AZURE_SERVICE_MESH_MODE_DISABLED:
46644665
raise ArgumentUsageError(
@@ -4712,6 +4713,97 @@ def _handle_ingress_gateways_asm(self, new_profile: ServiceMeshProfile) -> Tuple
47124713

47134714
return new_profile, updated
47144715

4716+
def _handle_egress_gateways_asm(self, new_profile: ServiceMeshProfile) -> Tuple[ServiceMeshProfile, bool]:
4717+
updated = False
4718+
enable_egress_gateway = self.raw_param.get("enable_egress_gateway", False)
4719+
disable_egress_gateway = self.raw_param.get("disable_egress_gateway", False)
4720+
istio_egressgateway_name = self.raw_param.get("istio_egressgateway_name", None)
4721+
istio_egressgateway_namespace = self.raw_param.get(
4722+
"istio_egressgateway_namespace",
4723+
CONST_AZURE_SERVICE_MESH_DEFAULT_EGRESS_NAMESPACE
4724+
)
4725+
gateway_configuration_name = self.raw_param.get("gateway_configuration_name", None)
4726+
4727+
# disallow disable egress gateway on a cluster with no asm enabled
4728+
if disable_egress_gateway:
4729+
if new_profile is None or new_profile.mode == CONST_AZURE_SERVICE_MESH_MODE_DISABLED:
4730+
raise ArgumentUsageError(
4731+
"Istio has not been enabled for this cluster, please refer to https://aka.ms/asm-aks-addon-docs "
4732+
"for more details on enabling Azure Service Mesh."
4733+
)
4734+
# deal with egress gateways
4735+
if enable_egress_gateway and disable_egress_gateway:
4736+
raise MutuallyExclusiveArgumentError(
4737+
"Cannot both enable and disable azure service mesh egress gateway at the same time.",
4738+
)
4739+
if enable_egress_gateway or disable_egress_gateway:
4740+
# if a gateway is enabled, enable the mesh
4741+
if enable_egress_gateway:
4742+
4743+
new_profile.mode = CONST_AZURE_SERVICE_MESH_MODE_ISTIO
4744+
if new_profile.istio is None:
4745+
new_profile.istio = self.models.IstioServiceMesh() # pylint: disable=no-member
4746+
updated = True
4747+
4748+
# Gateway configuration name is required for Istio egress gateway enablement
4749+
if not gateway_configuration_name:
4750+
raise RequiredArgumentMissingError("--gateway-configuration-name is required.")
4751+
4752+
if not istio_egressgateway_name:
4753+
raise RequiredArgumentMissingError("--istio-egressgateway-name is required.")
4754+
4755+
# ensure necessary fields
4756+
if new_profile.istio.components is None:
4757+
new_profile.istio.components = self.models.IstioComponents() # pylint: disable=no-member
4758+
updated = True
4759+
if new_profile.istio.components.egress_gateways is None:
4760+
new_profile.istio.components.egress_gateways = []
4761+
updated = True
4762+
# make update if the egress gateway already exists
4763+
egress_gateway_exists = False
4764+
for egress in new_profile.istio.components.egress_gateways:
4765+
if egress.name == istio_egressgateway_name and egress.namespace == istio_egressgateway_namespace:
4766+
if not egress.enabled and disable_egress_gateway:
4767+
raise ArgumentUsageError(
4768+
f'Egress gateway {istio_egressgateway_name} '
4769+
f'in namespace {istio_egressgateway_namespace} is already disabled.'
4770+
)
4771+
if egress.enabled and enable_egress_gateway:
4772+
if egress.gateway_configuration_name == gateway_configuration_name:
4773+
raise ArgumentUsageError(
4774+
f'Egress gateway {istio_egressgateway_name} '
4775+
f'in namespace {istio_egressgateway_namespace} is already enabled '
4776+
f'with gateway configuration name {gateway_configuration_name}.'
4777+
)
4778+
egress.enabled = enable_egress_gateway
4779+
# only update gateway configuration name for enabled egress gateways
4780+
if enable_egress_gateway:
4781+
egress.gateway_configuration_name = gateway_configuration_name
4782+
egress_gateway_exists = True
4783+
updated = True
4784+
break
4785+
4786+
# egress gateway doesn't exist, append
4787+
if not egress_gateway_exists:
4788+
if enable_egress_gateway:
4789+
new_profile.istio.components.egress_gateways.append(
4790+
self.models.IstioEgressGateway( # pylint: disable=no-member
4791+
enabled=enable_egress_gateway,
4792+
name=istio_egressgateway_name,
4793+
namespace=istio_egressgateway_namespace,
4794+
gateway_configuration_name=gateway_configuration_name,
4795+
)
4796+
)
4797+
elif disable_egress_gateway:
4798+
raise ArgumentUsageError(
4799+
f'Egress gateway {istio_egressgateway_name} '
4800+
f'in namespace {istio_egressgateway_namespace} does not exist, cannot disable.'
4801+
)
4802+
4803+
updated = True
4804+
4805+
return new_profile, updated
4806+
47154807
def _handle_enable_disable_asm(self, new_profile: ServiceMeshProfile) -> Tuple[ServiceMeshProfile, bool]:
47164808
updated = False
47174809
# enable/disable
@@ -4773,6 +4865,9 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile:
47734865
new_profile, updated_ingress_gateways_asm = self._handle_ingress_gateways_asm(new_profile)
47744866
updated |= updated_ingress_gateways_asm
47754867

4868+
new_profile, updated_egress_gateways_asm = self._handle_egress_gateways_asm(new_profile)
4869+
updated |= updated_egress_gateways_asm
4870+
47764871
new_profile, updated_pluginca_asm = self._handle_pluginca_asm(new_profile)
47774872
updated |= updated_pluginca_asm
47784873

0 commit comments

Comments
 (0)