From 166f55b81241f9198d4bf79fc69d6780817d8e87 Mon Sep 17 00:00:00 2001 From: Fuming Zhang Date: Thu, 25 Sep 2025 12:13:17 +1000 Subject: [PATCH 1/6] update --- .../azure/cli/command_modules/acs/custom.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index 3da42ea369f..fa89bf865aa 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1627,10 +1627,69 @@ def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, encoding='UTF-8') _print_or_merge_credentials( path, kubeconfig, overwrite_existing, context_name) + + # Check if kubeconfig requires kubelogin with devicecode and convert it + if uses_kubelogin_devicecode(kubeconfig): + if which("kubelogin"): + try: + # Run kubelogin convert-kubeconfig -l azurecli + subprocess.run(["kubelogin", "convert-kubeconfig", "-l", "azurecli"], + cwd=os.path.dirname(path), check=True) + logger.warning("Converted kubeconfig to use Azure CLI authentication.") + except subprocess.CalledProcessError as e: + logger.warning("Failed to convert kubeconfig with kubelogin: %s", str(e)) + except Exception as e: + logger.warning("Error running kubelogin: %s", str(e)) + else: + logger.warning("The kubeconfig uses devicecode authentication which requires kubelogin. " + "Please install kubelogin from https://github.com/Azure/kubelogin or run " + "'az aks install-cli' to install both kubectl and kubelogin. " + "If devicecode login fails, try running " + "'kubelogin convert-kubeconfig -l azurecli' to unblock yourself.") + except (IndexError, ValueError): raise CLIError("Fail to find kubeconfig file.") +def uses_kubelogin_devicecode(kubeconfig: str) -> bool: + try: + config = yaml.safe_load(kubeconfig) + + # Check if users section exists and has at least one user + if not config or not config.get('users') or len(config['users']) == 0: + return False + + first_user = config['users'][0] + user_info = first_user.get('user', {}) + exec_info = user_info.get('exec', {}) + + # Check if command is kubelogin + command = exec_info.get('command', '') + if 'kubelogin' not in command: + return False + + # Check if args contains --login and devicecode + args = exec_info.get('args', []) + has_login_flag = False + has_devicecode = False + + for i, arg in enumerate(args): + if arg == '--login' or arg == '-l': + has_login_flag = True + # Check if next arg is devicecode + if i + 1 < len(args) and args[i + 1] == 'devicecode': + has_devicecode = True + elif arg == 'devicecode' and has_login_flag: + has_devicecode = True + + return has_login_flag and has_devicecode + + except (yaml.YAMLError, KeyError, TypeError, AttributeError) as e: + # If there's any error parsing the kubeconfig, assume it doesn't require kubelogin + logger.debug("Error parsing kubeconfig: %s", str(e)) + return False + + def _handle_merge(existing, addition, key, replace): if not addition.get(key, False): return From 6c6d6a850f7a3a723186766de922274794abc39a Mon Sep 17 00:00:00 2001 From: Fuming Zhang Date: Thu, 25 Sep 2025 12:22:18 +1000 Subject: [PATCH 2/6] update test --- .../acs/tests/latest/test_aks_commands.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py index b67aec71c8c..870f9f0de1e 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py @@ -6621,6 +6621,17 @@ def test_aks_automatic_sku(self, resource_group, resource_group_location): ], ) + # get-credentials + fd, temp_path = tempfile.mkstemp() + self.kwargs.update({'file': temp_path}) + try: + self.cmd( + 'aks get-credentials -g {resource_group} -n {name} --file "{file}"') + self.assertGreater(os.path.getsize(temp_path), 0) + finally: + os.close(fd) + os.remove(temp_path) + # scale the cluster scale_cluster_cmd = ( "aks scale --resource-group={resource_group} --name={name} " From 44edebd028f858b5a93de9e502f58618cb6269e5 Mon Sep 17 00:00:00 2001 From: Fuming Zhang Date: Thu, 25 Sep 2025 13:18:01 +1000 Subject: [PATCH 3/6] fix style --- src/azure-cli/azure/cli/command_modules/acs/custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index fa89bf865aa..a456f7fb835 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1638,7 +1638,7 @@ def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, logger.warning("Converted kubeconfig to use Azure CLI authentication.") except subprocess.CalledProcessError as e: logger.warning("Failed to convert kubeconfig with kubelogin: %s", str(e)) - except Exception as e: + except Exception as e: # pylint: disable=broad-except logger.warning("Error running kubelogin: %s", str(e)) else: logger.warning("The kubeconfig uses devicecode authentication which requires kubelogin. " From bdf6fd263348f3df4ac5fcac63822cb1e13d55c5 Mon Sep 17 00:00:00 2001 From: FumingZhang <81607949+FumingZhang@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:21:42 +1000 Subject: [PATCH 4/6] Update src/azure-cli/azure/cli/command_modules/acs/custom.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/azure-cli/azure/cli/command_modules/acs/custom.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index a456f7fb835..2df258c2d33 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1675,15 +1675,10 @@ def uses_kubelogin_devicecode(kubeconfig: str) -> bool: for i, arg in enumerate(args): if arg == '--login' or arg == '-l': - has_login_flag = True # Check if next arg is devicecode if i + 1 < len(args) and args[i + 1] == 'devicecode': - has_devicecode = True - elif arg == 'devicecode' and has_login_flag: - has_devicecode = True - - return has_login_flag and has_devicecode - + return True + return False except (yaml.YAMLError, KeyError, TypeError, AttributeError) as e: # If there's any error parsing the kubeconfig, assume it doesn't require kubelogin logger.debug("Error parsing kubeconfig: %s", str(e)) From 2b19023d22e5913f9e666215808d365633ef0b37 Mon Sep 17 00:00:00 2001 From: Fuming Zhang Date: Thu, 25 Sep 2025 13:26:48 +1000 Subject: [PATCH 5/6] update --- .../azure/cli/command_modules/acs/custom.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index 2df258c2d33..e5c3cb2ac7a 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1670,14 +1670,11 @@ def uses_kubelogin_devicecode(kubeconfig: str) -> bool: # Check if args contains --login and devicecode args = exec_info.get('args', []) - has_login_flag = False - has_devicecode = False - - for i, arg in enumerate(args): - if arg == '--login' or arg == '-l': - # Check if next arg is devicecode - if i + 1 < len(args) and args[i + 1] == 'devicecode': - return True + # Join args into a string for easier pattern matching + args_str = ' '.join(args) + # Check for '--login devicecode' or '-l devicecode' + if '--login devicecode' in args_str or '-l devicecode' in args_str: + return True return False except (yaml.YAMLError, KeyError, TypeError, AttributeError) as e: # If there's any error parsing the kubeconfig, assume it doesn't require kubelogin From fc04dfa053905b7c32c59afd5242be3090fd0e19 Mon Sep 17 00:00:00 2001 From: Fuming Zhang Date: Thu, 25 Sep 2025 13:55:16 +1000 Subject: [PATCH 6/6] fix style --- .../azure/cli/command_modules/acs/custom.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index e5c3cb2ac7a..6d9b5a13b91 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1633,19 +1633,24 @@ def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, if which("kubelogin"): try: # Run kubelogin convert-kubeconfig -l azurecli - subprocess.run(["kubelogin", "convert-kubeconfig", "-l", "azurecli"], - cwd=os.path.dirname(path), check=True) + subprocess.run( + ["kubelogin", "convert-kubeconfig", "-l", "azurecli"], + cwd=os.path.dirname(path), + check=True, + ) logger.warning("Converted kubeconfig to use Azure CLI authentication.") except subprocess.CalledProcessError as e: logger.warning("Failed to convert kubeconfig with kubelogin: %s", str(e)) except Exception as e: # pylint: disable=broad-except logger.warning("Error running kubelogin: %s", str(e)) else: - logger.warning("The kubeconfig uses devicecode authentication which requires kubelogin. " - "Please install kubelogin from https://github.com/Azure/kubelogin or run " - "'az aks install-cli' to install both kubectl and kubelogin. " - "If devicecode login fails, try running " - "'kubelogin convert-kubeconfig -l azurecli' to unblock yourself.") + logger.warning( + "The kubeconfig uses devicecode authentication which requires kubelogin. " + "Please install kubelogin from https://github.com/Azure/kubelogin or run " + "'az aks install-cli' to install both kubectl and kubelogin. " + "If devicecode login fails, try running " + "'kubelogin convert-kubeconfig -l azurecli' to unblock yourself." + ) except (IndexError, ValueError): raise CLIError("Fail to find kubeconfig file.")