From c9b1da35be99e836f7428d6a853ef64453f7df34 Mon Sep 17 00:00:00 2001
From: xinyupang <xinyupang@microsoft.com>
Date: Wed, 8 Jan 2025 16:16:08 +0800
Subject: [PATCH] fix service connector

---
 src/containerapp/HISTORY.rst                  |  1 +
 .../azext_containerapp/_client_factory.py     |  6 ++
 src/containerapp/azext_containerapp/_utils.py | 13 ++++-
 .../containerapp_decorator.py                 | 57 ++++++++++---------
 4 files changed, 48 insertions(+), 29 deletions(-)

diff --git a/src/containerapp/HISTORY.rst b/src/containerapp/HISTORY.rst
index 7c9cade3bf6..af3cbf8b8bc 100644
--- a/src/containerapp/HISTORY.rst
+++ b/src/containerapp/HISTORY.rst
@@ -4,6 +4,7 @@ Release History
 ===============
 upcoming
 ++++++
+* 'az containerapp create/update': Fix an issue about `--bind`/`--unbind` when the cloud is not AzureCloud.
 * 'az containerapp debug': Open an SSH-like interactive shell within a container app debug console.
 * 'az containerapp connected-env certificate upload/remove': Support `--no-wait`.
 * 'az containerapp connected-env dapr-component set/remove': Support `--no-wait`.
diff --git a/src/containerapp/azext_containerapp/_client_factory.py b/src/containerapp/azext_containerapp/_client_factory.py
index 4ee278f73df..30eefa26013 100644
--- a/src/containerapp/azext_containerapp/_client_factory.py
+++ b/src/containerapp/azext_containerapp/_client_factory.py
@@ -152,3 +152,9 @@ def connected_k8s_client_factory(cli_ctx, subscription_id=None):
 
     r = get_mgmt_service_client(cli_ctx, ConnectedKubernetesClient, subscription_id=subscription_id)
     return r.connected_cluster
+
+
+def get_linker_client(cmd):
+    from azure.mgmt.servicelinker import ServiceLinkerManagementClient
+    linker_client = get_mgmt_service_client(cmd.cli_ctx, ServiceLinkerManagementClient, subscription_bound=False)
+    return linker_client
diff --git a/src/containerapp/azext_containerapp/_utils.py b/src/containerapp/azext_containerapp/_utils.py
index 1409658815d..3f4db609cef 100644
--- a/src/containerapp/azext_containerapp/_utils.py
+++ b/src/containerapp/azext_containerapp/_utils.py
@@ -117,6 +117,8 @@ def validate_binding_name(binding_name):
 
 
 def check_unique_bindings(cmd, service_connectors_def_list, service_bindings_def_list, resource_group_name, name):
+    from ._client_factory import get_linker_client
+
     linker_client = get_linker_client(cmd)
     containerapp_def = None
 
@@ -127,7 +129,10 @@ def check_unique_bindings(cmd, service_connectors_def_list, service_bindings_def
     all_bindings = []
 
     if containerapp_def:
-        managed_bindings = linker_client.linker.list(resource_uri=containerapp_def["id"])
+        if is_cloud_supported_by_service_connector(cmd.cli_ctx):
+            managed_bindings = linker_client.linker.list(resource_uri=containerapp_def["id"])
+        else:
+            managed_bindings = []
         service_binds = containerapp_def["properties"].get("template", {}).get("serviceBinds", [])
 
         if managed_bindings:
@@ -735,6 +740,12 @@ def is_cloud_supported_by_connected_env(cli_ctx):
     return False
 
 
+def is_cloud_supported_by_service_connector(cli_ctx):
+    if cli_ctx.cloud.name == 'AzureCloud':
+        return True
+    return False
+
+
 class AppType(Enum):
     ContainerApp = 1
     ContainerAppJob = 2
diff --git a/src/containerapp/azext_containerapp/containerapp_decorator.py b/src/containerapp/azext_containerapp/containerapp_decorator.py
index a47534dba62..06d625f65b2 100644
--- a/src/containerapp/azext_containerapp/containerapp_decorator.py
+++ b/src/containerapp/azext_containerapp/containerapp_decorator.py
@@ -29,7 +29,6 @@
                                                            is_registry_msi_system, validate_container_app_name, AppType,
                                                            safe_set, parse_metadata_flags, parse_auth_flags,
                                                            ensure_workload_profile_supported, _generate_secret_volume_name,
-                                                           get_linker_client,
                                                            safe_get, _update_revision_env_secretrefs, _add_or_update_tags, _populate_secret_values,
                                                            clean_null_values, _add_or_update_env_vars, _remove_env_vars, _get_acr_cred, _ensure_identity_resource_id,
                                                            create_acrpull_role_assignment, _ensure_location_allowed, get_default_workload_profile_name_from_env,
@@ -43,7 +42,7 @@
     ManagedServiceIdentity as ManagedServiceIdentityModel,
 )
 
-from azure.cli.core.commands.client_factory import get_subscription_id
+from azure.cli.core.commands.client_factory import get_subscription_id, get_mgmt_service_client
 from azure.mgmt.core.tools import parse_resource_id, is_valid_resource_id
 
 from knack.log import get_logger
@@ -52,7 +51,7 @@
 from msrest.exceptions import DeserializationError
 
 from ._clients import ManagedEnvironmentClient, ConnectedEnvironmentClient, ManagedEnvironmentPreviewClient
-from ._client_factory import handle_raw_exception, handle_non_404_status_code_exception
+from ._client_factory import handle_raw_exception, handle_non_404_status_code_exception, get_linker_client
 from ._models import (
     RegistryCredentials as RegistryCredentialsModel,
     ContainerResources as ContainerResourcesModel,
@@ -70,7 +69,7 @@
                                infer_runtime_option
                                )
 from ._utils import parse_service_bindings, check_unique_bindings, is_registry_msi_system_environment, \
-    env_has_managed_identity, create_acrpull_role_assignment_if_needed
+    env_has_managed_identity, create_acrpull_role_assignment_if_needed, is_cloud_supported_by_service_connector
 from ._validators import validate_create, validate_runtime
 from ._constants import (HELLO_WORLD_IMAGE,
                          CONNECTED_ENVIRONMENT_TYPE,
@@ -1592,25 +1591,26 @@ def _update_container_app_source(self, cmd, source, build_env_vars, registry_ser
 
     def post_process(self, r):
         # Delete managed bindings
-        linker_client = None
-        if self.get_argument_unbind_service_bindings():
-            linker_client = get_linker_client(self.cmd)
-            for item in self.get_argument_unbind_service_bindings():
-                while r["properties"]["provisioningState"].lower() == "inprogress":
-                    r = self.client.show(self.cmd, self.get_argument_resource_group_name(), self.get_argument_name())
-                    time.sleep(1)
-                linker_client.linker.begin_delete(resource_uri=r["id"], linker_name=item).result()
-
-        # Update managed bindings
-        if self.get_argument_service_connectors_def_list() is not None:
-            linker_client = get_linker_client(self.cmd) if linker_client is None else linker_client
-            for item in self.get_argument_service_connectors_def_list():
-                while r["properties"]["provisioningState"].lower() == "inprogress":
-                    r = self.client.show(self.cmd, self.get_argument_resource_group_name(), self.get_argument_name())
-                    time.sleep(1)
-                linker_client.linker.begin_create_or_update(resource_uri=r["id"],
-                                                            parameters=item["parameters"],
-                                                            linker_name=item["linker_name"]).result()
+        if is_cloud_supported_by_service_connector(self.cmd.cli_ctx):
+            linker_client = None
+            if self.get_argument_unbind_service_bindings():
+                linker_client = get_linker_client(self.cmd)
+                for item in self.get_argument_unbind_service_bindings():
+                    while r["properties"]["provisioningState"].lower() == "inprogress":
+                        r = self.client.show(self.cmd, self.get_argument_resource_group_name(), self.get_argument_name())
+                        time.sleep(1)
+                    linker_client.linker.begin_delete(resource_uri=r["id"], linker_name=item).result()
+
+            # Update managed bindings
+            if self.get_argument_service_connectors_def_list() is not None:
+                linker_client = get_linker_client(self.cmd) if linker_client is None else linker_client
+                for item in self.get_argument_service_connectors_def_list():
+                    while r["properties"]["provisioningState"].lower() == "inprogress":
+                        r = self.client.show(self.cmd, self.get_argument_resource_group_name(), self.get_argument_name())
+                        time.sleep(1)
+                    linker_client.linker.begin_create_or_update(resource_uri=r["id"],
+                                                                parameters=item["parameters"],
+                                                                linker_name=item["linker_name"]).result()
         return r
 
     def set_up_service_bindings(self):
@@ -1644,11 +1644,12 @@ def set_up_service_bindings(self):
             for update_item in service_bindings_def_list:
                 if service_bindings_used_map[update_item["name"]] is False:
                     # Check if it doesn't exist in existing service linkers
-                    managed_bindings = linker_client.linker.list(resource_uri=self.containerapp_def["id"])
-                    if managed_bindings:
-                        managed_bindings_list = [item.name for item in managed_bindings]
-                        if update_item["name"] in managed_bindings_list:
-                            raise ValidationError("Binding names across managed and dev services should be unique.")
+                    if is_cloud_supported_by_service_connector(self.cmd.cli_ctx):
+                        managed_bindings = linker_client.linker.list(resource_uri=self.containerapp_def["id"])
+                        if managed_bindings:
+                            managed_bindings_list = [item.name for item in managed_bindings]
+                            if update_item["name"] in managed_bindings_list:
+                                raise ValidationError("Binding names across managed and dev services should be unique.")
 
                     self.new_containerapp["properties"]["template"]["serviceBinds"].append(update_item)