From 29d57b70b6c84fcade5d4723d4cab0deca894787 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Thu, 31 Mar 2022 20:07:41 +1300 Subject: [PATCH 1/6] Use Kustomize for Periscope with Windows containers --- src/aks-preview/azext_aks_preview/_help.py | 5 +- src/aks-preview/azext_aks_preview/custom.py | 92 ++++---- .../deploymentyaml/__init__.py | 0 .../deploymentyaml/aks-periscope.yaml | 209 ------------------ src/aks-preview/setup.py | 2 +- 5 files changed, 60 insertions(+), 248 deletions(-) delete mode 100644 src/aks-preview/azext_aks_preview/deploymentyaml/__init__.py delete mode 100644 src/aks-preview/azext_aks_preview/deploymentyaml/aks-periscope.yaml diff --git a/src/aks-preview/azext_aks_preview/_help.py b/src/aks-preview/azext_aks_preview/_help.py index da908283d14..7aa25e7b3ef 100644 --- a/src/aks-preview/azext_aks_preview/_help.py +++ b/src/aks-preview/azext_aks_preview/_help.py @@ -852,7 +852,10 @@ for example, kube-system/deployment/tunnelfront. - name: --node-logs type: string - short-summary: The list of node logs to collect. For example, /var/log/cloud-init.log + short-summary: The list of node logs to collect for Linux nodes. For example, /var/log/cloud-init.log + - name: --node-logs-windows + type: string + short-summary: The list of node logs to collect for Windows nodes. For example, C:\\AzureData\\CustomDataSetupScript.log examples: - name: using storage account name and a shared access signature token with write permission text: az aks kollect -g MyResourceGroup -n MyManagedCluster --storage-account MyStorageAccount --sas-token "MySasToken" diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index e83b9804952..5d61794b563 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -1016,7 +1016,8 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals sas_token=None, container_logs=None, kube_objects=None, - node_logs=None): + node_logs=None, + node_logs_windows=None): colorama.init() mc = client.get(resource_group_name, name) @@ -1115,30 +1116,55 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals container_name = normalized_container_name[:len_of_container_name] sas_token = sas_token.strip('?') - deployment_yaml = _read_periscope_yaml() - deployment_yaml = deployment_yaml.replace( - "# ", storage_account_name) - deployment_yaml = deployment_yaml.replace("# ", - (base64.b64encode(bytes("?" + sas_token, 'ascii'))).decode('ascii')) - deployment_yaml = deployment_yaml.replace( - "# ", container_name) - - yaml_lines = deployment_yaml.splitlines() - for index, line in enumerate(yaml_lines): - if "DIAGNOSTIC_CONTAINERLOGS_LIST" in line and container_logs is not None: - yaml_lines[index] = line + ' ' + container_logs - if "DIAGNOSTIC_KUBEOBJECTS_LIST" in line and kube_objects is not None: - yaml_lines[index] = line + ' ' + kube_objects - if "DIAGNOSTIC_NODELOGS_LIST" in line and node_logs is not None: - yaml_lines[index] = line + ' ' + node_logs - deployment_yaml = '\n'.join(yaml_lines) - - fd, temp_yaml_path = tempfile.mkstemp() - temp_yaml_file = os.fdopen(fd, 'w+t') + + diag_config_vars = { + 'DIAGNOSTIC_CONTAINERLOGS_LIST': container_logs, + 'DIAGNOSTIC_KUBEOBJECTS_LIST': kube_objects, + 'DIAGNOSTIC_NODELOGS_LIST_LINUX': node_logs, + 'DIAGNOSTIC_NODELOGS_LIST_WINDOWS': node_logs_windows + } + + diag_content = "\n".join(f' - {k}="{v}"' for k,v in diag_config_vars.items() if v is not None) + + storage_config_vars = { + 'AZURE_BLOB_ACCOUNT_NAME': storage_account_name, + 'AZURE_BLOB_SAS_KEY': "?" + sas_token, + 'AZURE_BLOB_CONTAINER_NAME': container_name + } + + storage_content = "\n".join(f' - {k}="{v}"' for k,v in storage_config_vars.items()) + + kustomize_yaml = f""" +resources: +- https://github.com/peterbom/aks-periscope//deployment/base?ref=experiment/windows + +images: +- name: periscope-linux + newName: ghcr.io/peterbom/aks/periscope + newTag: 0.0.8 +- name: periscope-windows + newName: ghcr.io/peterbom/aks/periscope-win + newTag: 0.0.8 + +configMapGenerator: +- name: diagnostic-config + behavior: merge + literals: +{diag_content} + +secretGenerator: +- name: azureblob-secret + behavior: replace + literals: +{storage_content} +""" # .format(diag_content = diag_content, storage_content = storage_content) + + kustomize_folder = tempfile.mkdtemp() + kustomize_file_path = os.path.join(kustomize_folder, "kustomization.yaml") try: - temp_yaml_file.write(deployment_yaml) - temp_yaml_file.flush() - temp_yaml_file.close() + with os.fdopen(os.open(kustomize_file_path, os.O_RDWR | os.O_CREAT), 'w+t') as kustomize_file: + kustomize_file.write(kustomize_yaml) + try: print() print("Cleaning up aks-periscope resources if existing") @@ -1175,12 +1201,14 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals print() print("Deploying aks-periscope") - subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-f", - temp_yaml_path, "-n", "aks-periscope"], stderr=subprocess.STDOUT) + + subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-k", + kustomize_folder, "-n", "aks-periscope"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: raise CLIError(err.output) finally: - os.remove(temp_yaml_path) + os.remove(kustomize_file_path) + os.rmdir(kustomize_folder) print() @@ -1204,16 +1232,6 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals display_diagnostics_report(temp_kubeconfig_path) -def _read_periscope_yaml(): - curr_dir = os.path.dirname(os.path.realpath(__file__)) - periscope_yaml_file = os.path.join( - curr_dir, "deploymentyaml", "aks-periscope.yaml") - yaml_file = open(periscope_yaml_file, "r") - data_loaded = yaml_file.read() - - return data_loaded - - def aks_kanalyze(cmd, client, resource_group_name, name): colorama.init() diff --git a/src/aks-preview/azext_aks_preview/deploymentyaml/__init__.py b/src/aks-preview/azext_aks_preview/deploymentyaml/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/aks-preview/azext_aks_preview/deploymentyaml/aks-periscope.yaml b/src/aks-preview/azext_aks_preview/deploymentyaml/aks-periscope.yaml deleted file mode 100644 index 280d95bb225..00000000000 --- a/src/aks-preview/azext_aks_preview/deploymentyaml/aks-periscope.yaml +++ /dev/null @@ -1,209 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: aks-periscope ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: diagnostics.aks-periscope.azure.github.com -spec: - group: aks-periscope.azure.github.com - names: - kind: Diagnostic - plural: diagnostics - shortNames: - - apd - singular: diagnostic - scope: Namespaced - versions: - - name: v1 - schema: - openAPIV3Schema: - properties: - spec: - properties: - dns: - type: string - networkoutbound: - type: string - networkconfig: - type: string - type: object - type: object - served: true - storage: true ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: aks-periscope-service-account - namespace: aks-periscope ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: aks-periscope-role -rules: -- apiGroups: - - "" - - metrics.k8s.io - resources: - - pods - - nodes - verbs: - - get - - watch - - list -- apiGroups: - - aks-periscope.azure.github.com - resources: - - diagnostics - verbs: - - get - - watch - - list - - create - - patch -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - - list - - watch -- apiGroups: - - access.smi-spec.io - - specs.smi-spec.io - - split.smi-spec.io - resources: - - '*' - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: aks-periscope-role-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: aks-periscope-role -subjects: -- kind: ServiceAccount - name: aks-periscope-service-account - namespace: aks-periscope ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: aks-periscope-role-binding-view -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: view -subjects: -- kind: ServiceAccount - name: aks-periscope-service-account - namespace: aks-periscope ---- -apiVersion: v1 -data: - DIAGNOSTIC_CONTAINERLOGS_LIST: kube-system -kind: ConfigMap -metadata: - name: containerlogs-config - namespace: aks-periscope ---- -apiVersion: v1 -data: - DIAGNOSTIC_KUBEOBJECTS_LIST: kube-system/pod kube-system/service kube-system/deployment -kind: ConfigMap -metadata: - name: kubeobjects-config - namespace: aks-periscope ---- -apiVersion: v1 -data: - DIAGNOSTIC_NODELOGS_LIST: /var/log/azure/cluster-provision.log /var/log/cloud-init.log -kind: ConfigMap -metadata: - name: nodelogs-config - namespace: aks-periscope ---- -apiVersion: v1 -data: - AZURE_BLOB_SAS_KEY: # -kind: Secret -metadata: - name: azureblob-secret - namespace: aks-periscope -type: Opaque ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - app: aks-periscope - name: aks-periscope - namespace: aks-periscope -spec: - selector: - matchLabels: - app: aks-periscope - template: - metadata: - labels: - app: aks-periscope - spec: - containers: - - env: - - name: AZURE_BLOB_ACCOUNT_NAME - value: # - - name: AZURE_BLOB_CONTAINER_NAME - value: # - envFrom: - - configMapRef: - name: containerlogs-config - - configMapRef: - name: kubeobjects-config - - configMapRef: - name: nodelogs-config - - secretRef: - name: azureblob-secret - image: mcr.microsoft.com/aks/periscope:v0.6 - imagePullPolicy: Always - name: aks-periscope - resources: - limits: - cpu: 1000m - memory: 2000Mi - requests: - cpu: 250m - memory: 500Mi - securityContext: - privileged: true - volumeMounts: - - mountPath: /var/log - name: varlog - - mountPath: /run/systemd/resolve - name: resolvlog - - mountPath: /etchostlogs - name: etcvmlog - hostPID: true - nodeSelector: - kubernetes.io/os: linux - serviceAccountName: aks-periscope-service-account - volumes: - - hostPath: - path: /var/log - name: varlog - - hostPath: - path: /run/systemd/resolve - name: resolvlog - - hostPath: - path: /etc - name: etcvmlog diff --git a/src/aks-preview/setup.py b/src/aks-preview/setup.py index 047b058fb8e..91b2d2fb658 100644 --- a/src/aks-preview/setup.py +++ b/src/aks-preview/setup.py @@ -41,7 +41,7 @@ classifiers=CLASSIFIERS, packages=find_packages(exclude=["tests"]), package_data={ - "azext_aks_preview": ["azext_metadata.json", "deploymentyaml/*.yaml"] + "azext_aks_preview": ["azext_metadata.json"] }, install_requires=DEPENDENCIES, ) From 415be2a98adb2c1475595ed4e725e7f91d7041e0 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 1 Apr 2022 15:03:35 +1300 Subject: [PATCH 2/6] move kustomization generation to separate function --- src/aks-preview/azext_aks_preview/custom.py | 87 +++++++++++---------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index 5d61794b563..45e1622a3a1 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -1117,48 +1117,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals sas_token = sas_token.strip('?') - diag_config_vars = { - 'DIAGNOSTIC_CONTAINERLOGS_LIST': container_logs, - 'DIAGNOSTIC_KUBEOBJECTS_LIST': kube_objects, - 'DIAGNOSTIC_NODELOGS_LIST_LINUX': node_logs, - 'DIAGNOSTIC_NODELOGS_LIST_WINDOWS': node_logs_windows - } - - diag_content = "\n".join(f' - {k}="{v}"' for k,v in diag_config_vars.items() if v is not None) - - storage_config_vars = { - 'AZURE_BLOB_ACCOUNT_NAME': storage_account_name, - 'AZURE_BLOB_SAS_KEY': "?" + sas_token, - 'AZURE_BLOB_CONTAINER_NAME': container_name - } - - storage_content = "\n".join(f' - {k}="{v}"' for k,v in storage_config_vars.items()) - - kustomize_yaml = f""" -resources: -- https://github.com/peterbom/aks-periscope//deployment/base?ref=experiment/windows - -images: -- name: periscope-linux - newName: ghcr.io/peterbom/aks/periscope - newTag: 0.0.8 -- name: periscope-windows - newName: ghcr.io/peterbom/aks/periscope-win - newTag: 0.0.8 - -configMapGenerator: -- name: diagnostic-config - behavior: merge - literals: -{diag_content} - -secretGenerator: -- name: azureblob-secret - behavior: replace - literals: -{storage_content} -""" # .format(diag_content = diag_content, storage_content = storage_content) - + kustomize_yaml = get_kustomize_yaml("0.0.8", storage_account_name, sas_token, container_name, container_logs, kube_objects, node_logs, node_logs_windows) kustomize_folder = tempfile.mkdtemp() kustomize_file_path = os.path.join(kustomize_folder, "kustomization.yaml") try: @@ -1231,6 +1190,50 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals else: display_diagnostics_report(temp_kubeconfig_path) +def get_kustomize_yaml(periscope_version, + storage_account_name, + sas_token, + container_name, + container_logs=None, + kube_objects=None, + node_logs_linux=None, + node_logs_windows=None): + diag_config_vars = { + 'DIAGNOSTIC_CONTAINERLOGS_LIST': container_logs, + 'DIAGNOSTIC_KUBEOBJECTS_LIST': kube_objects, + 'DIAGNOSTIC_NODELOGS_LIST_LINUX': node_logs_linux, + 'DIAGNOSTIC_NODELOGS_LIST_WINDOWS': node_logs_windows + } + + diag_content = "\n".join(f' - {k}="{v}"' for k,v in diag_config_vars.items() if v is not None) + + # TODO: Change to MCR images + return f""" +resources: +- https://github.com/peterbom/aks-periscope//deployment/base?ref={periscope_version} + +images: +- name: periscope-linux + newName: ghcr.io/peterbom/aks/periscope + newTag: {periscope_version} +- name: periscope-windows + newName: ghcr.io/peterbom/aks/periscope-win + newTag: {periscope_version} + +configMapGenerator: +- name: diagnostic-config + behavior: merge + literals: +{diag_content} + +secretGenerator: +- name: azureblob-secret + behavior: replace + literals: + - AZURE_BLOB_ACCOUNT_NAME={storage_account_name} + - AZURE_BLOB_SAS_KEY=?{sas_token} + - AZURE_BLOB_CONTAINER_NAME={container_name} +""" def aks_kanalyze(cmd, client, resource_group_name, name): colorama.init() From 5c6cd7fc38f976b7beaf75b9304a9dbf28df36f5 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Mon, 4 Apr 2022 11:48:43 +1200 Subject: [PATCH 3/6] update resource definition to refer to Azure repo and MCR images --- src/aks-preview/azext_aks_preview/custom.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index 45e1622a3a1..c778e0e0dd6 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -1117,7 +1117,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals sas_token = sas_token.strip('?') - kustomize_yaml = get_kustomize_yaml("0.0.8", storage_account_name, sas_token, container_name, container_logs, kube_objects, node_logs, node_logs_windows) + kustomize_yaml = get_kustomize_yaml("v0.8", "0.0.8", storage_account_name, sas_token, container_name, container_logs, kube_objects, node_logs, node_logs_windows) kustomize_folder = tempfile.mkdtemp() kustomize_file_path = os.path.join(kustomize_folder, "kustomization.yaml") try: @@ -1190,7 +1190,8 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals else: display_diagnostics_report(temp_kubeconfig_path) -def get_kustomize_yaml(periscope_version, +def get_kustomize_yaml(periscope_release_tag, + periscope_image_version, storage_account_name, sas_token, container_name, @@ -1205,20 +1206,22 @@ def get_kustomize_yaml(periscope_version, 'DIAGNOSTIC_NODELOGS_LIST_WINDOWS': node_logs_windows } + # Create YAML list items for each config variable that has a value diag_content = "\n".join(f' - {k}="{v}"' for k,v in diag_config_vars.items() if v is not None) - # TODO: Change to MCR images + # Build a Kustomize overlay referencing a base for a known release, and using the images from MCR + # for that release. return f""" resources: -- https://github.com/peterbom/aks-periscope//deployment/base?ref={periscope_version} +- https://github.com/azure/aks-periscope//deployment/base?ref={periscope_release_tag} images: - name: periscope-linux - newName: ghcr.io/peterbom/aks/periscope - newTag: {periscope_version} + newName: mcr.microsoft.com/aks/periscope + newTag: {periscope_image_version} - name: periscope-windows - newName: ghcr.io/peterbom/aks/periscope-win - newTag: {periscope_version} + newName: mcr.microsoft.com/aks/periscope-win + newTag: {periscope_image_version} configMapGenerator: - name: diagnostic-config From 688eaa3dc9b77433e7bf7bf36d6fc31c6649b990 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Mon, 4 Apr 2022 15:36:37 +1200 Subject: [PATCH 4/6] use constants for periscope kustomize configuration --- src/aks-preview/azext_aks_preview/_consts.py | 6 +++ src/aks-preview/azext_aks_preview/custom.py | 39 +++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/aks-preview/azext_aks_preview/_consts.py b/src/aks-preview/azext_aks_preview/_consts.py index 04a656bf454..8beb31ee1fc 100644 --- a/src/aks-preview/azext_aks_preview/_consts.py +++ b/src/aks-preview/azext_aks_preview/_consts.py @@ -167,3 +167,9 @@ # refer https://docs.microsoft.com/en-us/rest/api/storageservices/ # naming-and-referencing-containers--blobs--and-metadata#container-names CONST_CONTAINER_NAME_MAX_LENGTH = 63 + +CONST_PERISCOPE_REPO_ORG = "azure" +CONST_PERISCOPE_CONTAINER_REGISTRY = "mcr.microsoft.com" +CONST_PERISCOPE_RELEASE_TAG = "v0.9" +CONST_PERISCOPE_IMAGE_VERSION = "0.0.9" +CONST_PERISCOPE_NAMESPACE = "aks-periscope" \ No newline at end of file diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index c778e0e0dd6..2e995d4ccc4 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -93,6 +93,11 @@ CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID, CONST_MONITORING_USING_AAD_MSI_AUTH, CONST_OPEN_SERVICE_MESH_ADDON_NAME, + CONST_PERISCOPE_REPO_ORG, + CONST_PERISCOPE_CONTAINER_REGISTRY, + CONST_PERISCOPE_RELEASE_TAG, + CONST_PERISCOPE_IMAGE_VERSION, + CONST_PERISCOPE_NAMESPACE, CONST_ROTATION_POLL_INTERVAL, CONST_SCALE_DOWN_MODE_DELETE, CONST_SCALE_SET_PRIORITY_REGULAR, @@ -1117,7 +1122,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals sas_token = sas_token.strip('?') - kustomize_yaml = get_kustomize_yaml("v0.8", "0.0.8", storage_account_name, sas_token, container_name, container_logs, kube_objects, node_logs, node_logs_windows) + kustomize_yaml = get_kustomize_yaml(storage_account_name, sas_token, container_name, container_logs, kube_objects, node_logs, node_logs_windows) kustomize_folder = tempfile.mkdtemp() kustomize_file_path = os.path.join(kustomize_folder, "kustomization.yaml") try: @@ -1126,11 +1131,11 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals try: print() - print("Cleaning up aks-periscope resources if existing") + print(f"Cleaning up aks-periscope resources if existing") subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "serviceaccount,configmap,daemonset,secret", - "--all", "-n", "aks-periscope", "--ignore-not-found"], + "--all", "-n", CONST_PERISCOPE_NAMESPACE, "--ignore-not-found"], stderr=subprocess.STDOUT) subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", @@ -1150,7 +1155,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "--all", - "apd", "-n", "aks-periscope", "--ignore-not-found"], + "apd", "-n", CONST_PERISCOPE_NAMESPACE, "--ignore-not-found"], stderr=subprocess.DEVNULL) subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", @@ -1159,10 +1164,10 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals stderr=subprocess.STDOUT) print() - print("Deploying aks-periscope") + print(f"Deploying aks-periscope") subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-k", - kustomize_folder, "-n", "aks-periscope"], stderr=subprocess.STDOUT) + kustomize_folder, "-n", CONST_PERISCOPE_NAMESPACE], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: raise CLIError(err.output) finally: @@ -1190,9 +1195,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals else: display_diagnostics_report(temp_kubeconfig_path) -def get_kustomize_yaml(periscope_release_tag, - periscope_image_version, - storage_account_name, +def get_kustomize_yaml(storage_account_name, sas_token, container_name, container_logs=None, @@ -1213,15 +1216,17 @@ def get_kustomize_yaml(periscope_release_tag, # for that release. return f""" resources: -- https://github.com/azure/aks-periscope//deployment/base?ref={periscope_release_tag} +- https://github.com/{CONST_PERISCOPE_REPO_ORG}/aks-periscope//deployment/base?ref={CONST_PERISCOPE_RELEASE_TAG} + +namespace: {CONST_PERISCOPE_NAMESPACE} images: - name: periscope-linux - newName: mcr.microsoft.com/aks/periscope - newTag: {periscope_image_version} + newName: {CONST_PERISCOPE_CONTAINER_REGISTRY}/aks/periscope + newTag: {CONST_PERISCOPE_IMAGE_VERSION} - name: periscope-windows - newName: mcr.microsoft.com/aks/periscope-win - newTag: {periscope_image_version} + newName: {CONST_PERISCOPE_CONTAINER_REGISTRY}/aks/periscope-win + newTag: {CONST_PERISCOPE_IMAGE_VERSION} configMapGenerator: - name: diagnostic-config @@ -2619,7 +2624,7 @@ def display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-ma if not apds_created: apd = subprocess.check_output( ["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", - "apd", "-n", "aks-periscope", "--no-headers"], + "apd", "-n", CONST_PERISCOPE_NAMESPACE, "--no-headers"], universal_newlines=True ) apd_lines = apd.splitlines() @@ -2643,14 +2648,14 @@ def display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-ma network_config = subprocess.check_output( ["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "apd", apdName, "-n", - "aks-periscope", "-o=jsonpath={.spec.networkconfig}"], + 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, "get", "apd", apdName, "-n", - "aks-periscope", "-o=jsonpath={.spec.networkoutbound}"], + CONST_PERISCOPE_NAMESPACE, "-o=jsonpath={.spec.networkoutbound}"], universal_newlines=True) logger.debug('Network status for node %s is %s', node_name, network_status) From fb0c44325eb77542e1af9d6634e68f440b3e1856 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 27 May 2022 11:48:05 +1200 Subject: [PATCH 5/6] fix static analysis errors --- src/aks-preview/azext_aks_preview/_consts.py | 2 +- src/aks-preview/azext_aks_preview/custom.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aks-preview/azext_aks_preview/_consts.py b/src/aks-preview/azext_aks_preview/_consts.py index 8beb31ee1fc..1bc36923f8d 100644 --- a/src/aks-preview/azext_aks_preview/_consts.py +++ b/src/aks-preview/azext_aks_preview/_consts.py @@ -172,4 +172,4 @@ CONST_PERISCOPE_CONTAINER_REGISTRY = "mcr.microsoft.com" CONST_PERISCOPE_RELEASE_TAG = "v0.9" CONST_PERISCOPE_IMAGE_VERSION = "0.0.9" -CONST_PERISCOPE_NAMESPACE = "aks-periscope" \ No newline at end of file +CONST_PERISCOPE_NAMESPACE = "aks-periscope" diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index 2e995d4ccc4..9fb288b3ce6 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -1165,7 +1165,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals print() print(f"Deploying aks-periscope") - + subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-k", kustomize_folder, "-n", CONST_PERISCOPE_NAMESPACE], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: @@ -1195,6 +1195,7 @@ def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals else: display_diagnostics_report(temp_kubeconfig_path) + def get_kustomize_yaml(storage_account_name, sas_token, container_name, @@ -1210,7 +1211,7 @@ def get_kustomize_yaml(storage_account_name, } # Create YAML list items for each config variable that has a value - diag_content = "\n".join(f' - {k}="{v}"' for k,v in diag_config_vars.items() if v is not None) + diag_content = "\n".join(f' - {k}="{v}"' for k, v in diag_config_vars.items() if v is not None) # Build a Kustomize overlay referencing a base for a known release, and using the images from MCR # for that release. @@ -1243,6 +1244,7 @@ def get_kustomize_yaml(storage_account_name, - AZURE_BLOB_CONTAINER_NAME={container_name} """ + def aks_kanalyze(cmd, client, resource_group_name, name): colorama.init() From dea2434655015b3fa4dad5145a491d7c349355a5 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Thu, 2 Jun 2022 12:39:33 +1200 Subject: [PATCH 6/6] add e2e test for kollect command --- .../tests/latest/test_aks_commands.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py b/src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py index c907db59c2d..ca1dc556f5e 100644 --- a/src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py +++ b/src/aks-preview/azext_aks_preview/tests/latest/test_aks_commands.py @@ -5,11 +5,14 @@ import base64 import os +import pty +import subprocess import tempfile from azure.cli.testsdk import ( ScenarioTest, live_only) from azure.cli.command_modules.acs._format import version_to_tuple +from azure.cli.testsdk import CliTestError from azure.cli.testsdk.scenario_tests import AllowLargeResponse from knack.util import CLIError from azure.core.exceptions import HttpResponseError @@ -4442,3 +4445,82 @@ def test_aks_draft_with_manifest(self): update_cmd = f'aks draft update --path={tmp_dir} --destination={tmp_dir} --host=testHost --certificate=testKV' self.cmd(update_cmd) assert os.path.isfile(f'{tmp_dir}/manifests/service.yaml') + + @live_only() # because we're downloading a binary, and we're not testing the output of any ARM requests. + @AKSCustomResourceGroupPreparer(random_name_length=17, name_prefix='clitest', location='centraluseuap') + def test_aks_kollect(self, resource_group, resource_group_location): + aks_name = self.create_random_name('cliakstest', 16) + stg_acct_name = self.create_random_name('cliaksteststg', 24) + self.kwargs.update({ + 'resource_group': resource_group, + 'location': resource_group_location, + 'aks_name': aks_name, + 'stg_acct_name': stg_acct_name, + 'ssh_key_value': self.generate_ssh_keys() + }) + + create_aks_cmd = 'aks create --resource-group={resource_group} --name={aks_name} --location={location} --ssh-key-value={ssh_key_value} -o json' + self.cmd(create_aks_cmd, checks=[ + self.check('provisioningState', 'Succeeded') + ]) + + create_stg_cmd = 'storage account create --resource-group={resource_group} --name={stg_acct_name} --location={location} -o json' + self.cmd(create_stg_cmd, checks=[ + self.check('provisioningState', 'Succeeded') + ]) + + # Install kubectl (required by the 'kollect' command, and to perform verification of deployed resources). + try: + subprocess.call(['az', 'aks', 'install-cli']) + except subprocess.CalledProcessError as err: + raise CliTestError(f"Failed to install kubectl with error: '{err}'") + + # Create kubeconfig file + fd, kubeconfig_path = tempfile.mkstemp() + self.kwargs.update({ 'kubeconfig_path': kubeconfig_path }) + try: + get_credential_cmd = 'aks get-credentials --resource-group={resource_group} --name={aks_name} -f {kubeconfig_path}' + self.cmd(get_credential_cmd) + finally: + os.close(fd) + + # The kollect command is interactive, with two prompts requiring 'y|n' followed by newline. + # The prompting library used by the CLI checks for the presence of a TTY, so just passing these as input is not + # sufficient and will raise an exception; we also need to attach a pseudo-TTY to the process. + ptyInFd, ptyOutFd = pty.openpty() + try: + with os.fdopen(ptyInFd, 'w', closefd=False) as ptyIn: + kollect_cmd = ['az', 'aks', 'kollect', '--resource-group', resource_group, '--name', aks_name, '--storage-account', stg_acct_name] + + # For this test, the first input should be 'y' (to confirm), and the second should be 'n' (to see analysis results). + # Write these to our PTY (they will be buffered until the command attempts to read them). + kollect_stdin_responses = ['y\n', 'n\n'] + ptyIn.write(''.join(kollect_stdin_responses)) + + kollect_output = subprocess.check_output(kollect_cmd, stdin=ptyOutFd, stderr=subprocess.STDOUT, text=True) + except subprocess.CalledProcessError as err: + raise CliTestError(f"Failed to kollect with exit code {err.returncode}. Output:\n{err.output}") + finally: + os.close(ptyOutFd) + os.close(ptyInFd) + + # Check expected output of kollect command + for pattern in [ + f"This will deploy a daemon set to your cluster to collect logs and diagnostic information and save them to the storage account {stg_acct_name}", + f"Your logs are being uploaded to storage account {stg_acct_name}", + f"You can run 'az aks kanalyze -g {resource_group} -n {aks_name}' anytime to check the analysis results" + ]: + if not pattern in kollect_output: + raise CliTestError(f"Output from kollect did not contain '{pattern}'. Output:\n{kollect_output}") + + # Invoke kubectl to get the daemonsets deployed to the cluster + k_get_daemonset_cmd = ["kubectl", "get", "daemonset", "-n", "aks-periscope", "-o", "name", "--kubeconfig", kubeconfig_path] + k_get_daemonset_output = subprocess.check_output(k_get_daemonset_cmd, text=True) + + # Check expected output of 'kubectl get daemonset' command + for pattern in [ + "daemonset.apps/aks-periscope", + "daemonset.apps/aks-periscope-win" + ]: + if not pattern in k_get_daemonset_output: + raise CliTestError(f"Output from 'kubectl get daemonset' did not contain '{pattern}'. Output:\n{k_get_daemonset_output}")