Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* `az aks kollect`, `az aks kanalyze`, `az aks get-credentials` and `az aks bastion tunnel`: Use resolved executable paths consistently.
* `az aks bastion tunnel`: Report unsuccessful tunnel process exits instead of returning success.
* `az aks bastion tunnel`: Identify interactive shells by executable name rather than directory names.
* `az aks create`: Add `--enable-disk-driver` so the AzureDisk CSI Driver can be enabled explicitly on create. The driver is already on by default, but `storageProfile.diskCSIDriver` was omitted from the create request unless `--disable-disk-driver` was passed, which blocked features that validate `storageProfile.diskCSIDriver.enabled` on the request body. `az aks update` already accepted this flag.

22.0.0b12
Expand Down
30 changes: 22 additions & 8 deletions src/aks-preview/azext_aks_preview/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,31 @@ def reset_agentpool_to_name_and_mode(agentpool, mode):


def which(binary):
path_var = os.getenv('PATH')
if platform.system() == 'Windows':
binary = binary + '.exe'
parts = path_var.split(';')
"""Resolve an explicit executable path or search absolute directories in PATH."""
is_windows = platform.system() == 'Windows'
binaries = [binary]
if is_windows and not os.path.splitext(binary)[1]:
extensions = os.getenv('PATHEXT') or '.COM;.EXE;.BAT;.CMD'
binaries = [binary + extension for extension in extensions.split(';') if extension]

explicit_path = bool(os.path.dirname(binary))
if explicit_path:
parts = ['']
else:
parts = path_var.split(':')
parts = os.getenv('PATH', '').split(';' if is_windows else ':')

for part in parts:
bin_path = os.path.join(part, binary)
if os.path.exists(bin_path) and os.path.isfile(bin_path) and os.access(bin_path, os.X_OK):
return bin_path
if is_windows:
part = part.strip('"')
# Empty, relative and drive-relative entries depend on the working directory.
if not explicit_path and (
not os.path.isabs(part) or (is_windows and not os.path.splitdrive(part)[0])
):
continue
for executable in binaries:
bin_path = os.path.abspath(os.path.join(part, executable))
if os.path.isfile(bin_path) and os.access(bin_path, os.X_OK):
return bin_path

return None

Expand Down
38 changes: 22 additions & 16 deletions src/aks-preview/azext_aks_preview/aks_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ def aks_kollect_cmd(cmd, # pylint: disable=too-many-statements,too-many-local

mc = client.get(resource_group_name, name)

if not which('kubectl'):
kubectl_path = which('kubectl')
if not kubectl_path:
raise CLIError('Can not find kubectl executable in PATH')

storage_account_id = None
Expand Down Expand Up @@ -166,40 +167,40 @@ def aks_kollect_cmd(cmd, # pylint: disable=too-many-statements,too-many-local
print()
print("Cleaning up aks-periscope resources if existing")

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"serviceaccount,configmap,daemonset,secret",
"--all", "-n", CONST_PERISCOPE_NAMESPACE, "--ignore-not-found"],
stderr=subprocess.STDOUT)

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"ClusterRoleBinding",
"aks-periscope-role-binding", "--ignore-not-found"],
stderr=subprocess.STDOUT)

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"ClusterRoleBinding",
"aks-periscope-role-binding-view", "--ignore-not-found"],
stderr=subprocess.STDOUT)

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"ClusterRole",
"aks-periscope-role", "--ignore-not-found"],
stderr=subprocess.STDOUT)

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"--all",
"apd", "-n", CONST_PERISCOPE_NAMESPACE, "--ignore-not-found"],
stderr=subprocess.DEVNULL)

subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete",
subprocess.call([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "delete",
"CustomResourceDefinition",
"diagnostics.aks-periscope.azure.github.com", "--ignore-not-found"],
stderr=subprocess.STDOUT)

print()
print("Deploying aks-periscope")

subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-k",
subprocess.check_output([kubectl_path, "--kubeconfig", temp_kubeconfig_path, "apply", "-k",
kustomize_folder, "-n", CONST_PERISCOPE_NAMESPACE], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
raise CLIError(err.output) from err
Expand Down Expand Up @@ -249,18 +250,22 @@ def _get_temp_kubeconfig_path(cmd, client, resource_group_name: str, name: str,

if has_aad_profile:
# The current credentials require interactive login. We need to use kubelogin to update the kubeconfig credential.
if not which('kubelogin'):
kubelogin_path = which('kubelogin')
if not kubelogin_path:
# No kubelogin found...but we can install it if the user wants.
if not prompt_y_n('Can not find kubelogin executable in PATH. Install now?', default="y"):
# The user doesn't want us to install kubelogin automatically, so we cannot continue.
raise CLIError('kubelogin not found. Use az aks install-cli to install.')

# Install kubelogin
kubelogin_install_location = _get_default_install_location('kubelogin')
k8s_install_kubelogin(cmd, 'latest', kubelogin_install_location)
if not kubelogin_install_location:
raise CLIError('Can not determine kubelogin install location. Use az aks install-cli to install.')
kubelogin_path = os.path.abspath(kubelogin_install_location)
k8s_install_kubelogin(cmd, 'latest', kubelogin_path)

# kubelogin is installed. Run it to populate user credentials that don't require interactive login.
subprocess.check_output(["kubelogin", "convert-kubeconfig", "--kubeconfig", temp_kubeconfig_path, "--login", "azurecli"], stderr=subprocess.STDOUT)
subprocess.check_output([kubelogin_path, "convert-kubeconfig", "--kubeconfig", temp_kubeconfig_path, "--login", "azurecli"], stderr=subprocess.STDOUT)

return temp_kubeconfig_path

Expand Down Expand Up @@ -388,11 +393,12 @@ def _is_windows_hpc_supported(agent_pools):


def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-many-statements
if not which('kubectl'):
kubectl_path = which('kubectl')
if not kubectl_path:
raise CLIError('Can not find kubectl executable in PATH')

nodes = subprocess.check_output(
["kubectl", "--kubeconfig", temp_kubeconfig_path,
[kubectl_path, "--kubeconfig", temp_kubeconfig_path,
"get", "node", "--no-headers"],
universal_newlines=True)
logger.debug(nodes)
Expand Down Expand Up @@ -422,7 +428,7 @@ def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-m
for retry in range(0, max_retry):
if not apds_created:
apd = subprocess.check_output(
["kubectl", "--kubeconfig", temp_kubeconfig_path, "get",
[kubectl_path, "--kubeconfig", temp_kubeconfig_path, "get",
"apd", "-n", CONST_PERISCOPE_NAMESPACE, "--no-headers"],
universal_newlines=True
)
Expand All @@ -443,14 +449,14 @@ def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-m
apdName = "aks-periscope-diagnostic-" + node_name
try:
network_config = subprocess.check_output(
["kubectl", "--kubeconfig", temp_kubeconfig_path,
[kubectl_path, "--kubeconfig", temp_kubeconfig_path,
"get", "apd", apdName, "-n",
CONST_PERISCOPE_NAMESPACE, "-o=jsonpath={.spec.networkconfig}"],
universal_newlines=True)
logger.debug('Dns status for node %s is %s',
node_name, network_config)
network_status = subprocess.check_output(
["kubectl", "--kubeconfig", temp_kubeconfig_path,
[kubectl_path, "--kubeconfig", temp_kubeconfig_path,
"get", "apd", apdName, "-n",
CONST_PERISCOPE_NAMESPACE, "-o=jsonpath={.spec.networkoutbound}"],
universal_newlines=True)
Expand Down
Loading
Loading