diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 319150e4738..305882789d2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -35,20 +35,19 @@ jobs: TSLint: false ToolLogsNotFoundAction: 'Standard' -# - job: SourceStatic -# displayName: "Source Code Static Check" -# pool: -# vmImage: 'ubuntu-16.04' -# steps: -# - task: UsePythonVersion@0 -# displayName: 'Use Python 3.7' -# inputs: -# versionSpec: 3.7 -# - task: Bash@3 -# displayName: "Source Code Static Check" -# inputs: -# targetType: 'filePath' -# filePath: scripts/ci/test_static.sh +- job: StaticAnalysis + displayName: "Static Analysis" + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.6' + inputs: + versionSpec: 3.6 + - bash: pip install wheel==0.30.0 pylint==1.9.5 flake8 requests + displayName: 'Install wheel, pylint, flake8, requests' + - bash: python scripts/ci/source_code_static_analysis.py + displayName: "Static Analysis" - job: IndexVerify displayName: "Verify Extensions Index" diff --git a/pylintrc b/pylintrc index 55c4e7ce3d7..8ea2c308844 100644 --- a/pylintrc +++ b/pylintrc @@ -4,10 +4,30 @@ reports=no [MESSAGES CONTROL] # For all codes, run 'pylint --list-msgs' or go to 'https://pylint.readthedocs.io/en/latest/reference_guide/features.html' -# locally-disabled: Warning locally suppressed using disable-msg -# cyclic-import: because of https://github.com/PyCQA/pylint/issues/850 -# too-many-arguments: Due to the nature of the CLI many commands have large arguments set which reflect in large arguments set in corresponding methods. -disable=missing-docstring,locally-disabled,fixme,cyclic-import,too-many-arguments,invalid-name,duplicate-code +# +# locally-disabled: +# Warning locally suppressed using disable-msg +# +# cyclic-import: +# because of https://github.com/PyCQA/pylint/issues/850 +# +# too-many-arguments: +# Due to the nature of the CLI many commands have large arguments set which reflect in large arguments set in corresponding methods. +# +# too-many-lines: +# Due to unreasonable structure and history debut, files get expanding very large +# +# useless-object-inheritance: +# Due to some classes inherits from __builtin__.object(), can be safely removed from bases in python3 +# +disable=missing-docstring, + locally-disabled, + fixme, + cyclic-import, + too-many-arguments, + invalid-name, + duplicate-code, + useless-object-inheritance [TYPECHECK] # For Azure CLI extensions, we ignore some import errors as they'll be available in the environment of the CLI diff --git a/scripts/ci/source_code_static_analysis.py b/scripts/ci/source_code_static_analysis.py new file mode 100644 index 00000000000..3b3e391004f --- /dev/null +++ b/scripts/ci/source_code_static_analysis.py @@ -0,0 +1,154 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from __future__ import print_function + +import os +import sys +import multiprocessing + +from pylint import lint +from flake8.main import application + +from util import get_repo_root + +# import argparse +# from verify_codeowners import main as _verify_codeowners +# from verify_license import main as _verify_license + + +SDK_FILE_MARKER = r"# Code generated by Microsoft (R) AutoRest Code Generator." + + +# build list of sdk files +def _get_sdk_module_list(root_dir): + dir_paths = [os.path.join(root_dir, path) for path in os.listdir(root_dir)] + sdk_files = [] + + for path in dir_paths: + if os.path.isdir(path): + sdk_files.extend(_get_sdk_module_list(path)) + elif _is_sdk_file(path): + sdk_files.append(os.path.dirname(path)) + + return sdk_files + + +# check if the current file is a python sdk file +def _is_sdk_file(file_path): + # don't bother opening non-python files. e.g pyc files. + if not file_path.endswith(".py"): + return False + with open(file_path, encoding='utf-8') as f: + for line in f: + if SDK_FILE_MARKER in line: + return True + return False + + +# build list of modules that start with prefix "azext_" in the src +def _get_azext_module_paths(root_dir): + src_root = os.path.join(root_dir, "src") + src_paths = [os.path.join(src_root, path) for path in os.listdir(src_root)] + ext_modules = [] + for ext_root in src_paths: + if os.path.isdir(ext_root): + paths = [path for path in os.listdir(ext_root)] + ext_modules.extend([os.path.join(ext_root, path) for path in paths if path.startswith("azext_")]) + return ext_modules + + +# build list of python ci scripts +def _get_ci_py_file_paths(directory): + return [os.path.join(directory, path) for path in os.listdir(directory) if path.endswith(".py")] + + +def _run_pylint(module_paths, ignored_modules=None, rcfile=None, cpu_count=1): + pylint_opts = [] + + if ignored_modules: + pylint_opts.append("--ignore={}".format(ignored_modules)) + if rcfile: + pylint_opts.append("--rcfile={}".format(rcfile)) + + pylint_opts.append("--jobs={}".format(cpu_count)) + pylint_opts.extend(module_paths) + + try: + lint.Run(pylint_opts) + except SystemExit as se: + # 0: everything is fine + # 1: Fatal message issued + # 2: Error message issued + # 4: Warning message issued + # 8: Refactor message issued + # 16: Convention message issued + # 32: Usage error + if se.code not in [0, 8, 16, 24]: + sys.exit(se.code) + + +def _run_flake8(module_paths, config_file=None): + flake8_opts = ["--statistics"] + + if config_file: + flake8_opts.append("--append-config={}".format(config_file)) + + flake8_opts.extend(module_paths) + + app = application.Application() + app.run(flake8_opts) + try: + app.exit() + except SystemExit: + pass + + if app.result_count > 0 or app.catastrophic_failure: + sys.exit(app.result_count or 1) + + +def main(): + cpu_count = multiprocessing.cpu_count() + + root_dir = get_repo_root() + sdk_modules = _get_sdk_module_list(root_dir) + sdk_modules.append("vendored_sdks") + module_paths = _get_azext_module_paths(root_dir) + + # scripts_dir = os.path.join(root_dir, "scripts") + # ci_files = _get_ci_py_file_paths(os.path.join(scripts_dir, "ci")) + + rc_file = os.path.join(root_dir, "pylintrc") + # config_file = os.path.join(root_dir, "flake8") + + print("\nRunning pylint on extensions...") + _run_pylint(module_paths, ",".join(sdk_modules), rc_file, cpu_count) + print("Pylint OK.\n") + + # print("Running flake8 on extensions...") + # _run_flake8(module_paths, config_file) + # print("Flake8 OK.\n") + # + # print("Running pylint on CI scripts...") + # _run_pylint(ci_files, rcfile=rcfile, cpu_count=cpu_count) + # print("Pylint OK.\n") + # + # print("Running flake8 on CI scripts...") + # _run_flake8(ci_files, config_file=config_file) + # print("Pylint OK.\n") + # + # print("Other Static checks...") + # + # _verify_codeowners() + # + # parser = argparse.ArgumentParser() + # parser.add_argument('excluded_paths', nargs='*') + # _verify_license(parser.parse_args()) + + print("All static checks successful!") + + +if __name__ == "__main__": + main() diff --git a/scripts/ci/test_static.py b/scripts/ci/test_static.py index 99b6dce33ab..09b47d98d73 100644 --- a/scripts/ci/test_static.py +++ b/scripts/ci/test_static.py @@ -41,7 +41,7 @@ def _is_sdk_file(file_path): # don't bother opening non-python files. e.g pyc files. if not file_path.endswith(".py"): return False - with open(file_path) as f: + with open(file_path, encoding='utf-8') as f: for line in f: if SDK_FILE_MARKER in line: return True diff --git a/scripts/ci/test_static.sh b/scripts/ci/test_static.sh index 272c6320a5c..716b8400ac4 100755 --- a/scripts/ci/test_static.sh +++ b/scripts/ci/test_static.sh @@ -24,4 +24,4 @@ flake8 --append-config=./.flake8 ./scripts/ci/*.py # Other static checks python ./scripts/ci/verify_codeowners.py -python ./scripts/ci/verify_license.py +python ./scripts/ci/verify_license.py \ 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 2055f6ca291..6e2e1b50985 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -3,6 +3,8 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +# pylint: disable=too-many-lines + from __future__ import print_function import binascii @@ -78,9 +80,6 @@ logger = get_logger(__name__) -# pylint:disable=too-many-lines,unused-argument - - def which(binary): path_var = os.getenv('PATH') if platform.system() == 'Windows': @@ -534,9 +533,13 @@ def subnet_role_assignment_exists(cli_ctx, scope): return False -# pylint: disable=too-many-statements -def aks_browse(cmd, client, resource_group_name, name, disable_browser=False, - listen_address='127.0.0.1', listen_port='8001'): +def aks_browse(cmd, # pylint: disable=too-many-statements + client, + resource_group_name, + name, + disable_browser=False, + listen_address='127.0.0.1', + listen_port='8001'): if not which('kubectl'): raise CLIError('Can not find kubectl executable in PATH') @@ -628,9 +631,11 @@ def _trim_nodepoolname(nodepool_name): return nodepool_name[:12] -# pylint: disable=too-many-statements -# pylint: disable=too-many-branches -def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint: disable=too-many-locals +def aks_create(cmd, # pylint: disable=too-many-locals,too-many-statements,too-many-branches + client, + resource_group_name, + name, + ssh_key_value, dns_name_prefix=None, location=None, admin_username="azureuser", @@ -897,7 +902,11 @@ def aks_create(cmd, client, resource_group_name, name, ssh_key_value, # pylint: raise retry_exception -def aks_update(cmd, client, resource_group_name, name, enable_cluster_autoscaler=False, +def aks_update(cmd, # pylint: disable=too-many-statements,too-many-branches,too-many-locals + client, + resource_group_name, + name, + enable_cluster_autoscaler=False, disable_cluster_autoscaler=False, update_cluster_autoscaler=False, min_count=None, max_count=None, no_wait=False, @@ -1026,7 +1035,7 @@ def aks_update(cmd, client, resource_group_name, name, enable_cluster_autoscaler return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, name, instance) -def aks_show(cmd, client, resource_group_name, name): +def aks_show(cmd, client, resource_group_name, name): # pylint: disable=unused-argument mc = client.get(resource_group_name, name) return _remove_nulls([mc])[0] @@ -1056,7 +1065,11 @@ def _remove_nulls(managed_clusters): return managed_clusters -def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, +def aks_get_credentials(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + name, + admin=False, path=os.path.join(os.path.expanduser('~'), '.kube', 'config'), overwrite_existing=False): credentialResults = None @@ -1085,7 +1098,10 @@ def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, # pylint: disable=line-too-long -def aks_kollect(cmd, client, resource_group_name, name, +def aks_kollect(cmd, # pylint: disable=too-many-statements,too-many-locals + client, + resource_group_name, + name, storage_account=None, sas_token=None, container_logs=None, @@ -1130,7 +1146,8 @@ def aks_kollect(cmd, client, resource_group_name, name, readonly_sas_token = None if sas_token is None: storage_client = cf_storage(cmd.cli_ctx, parsed_storage_account['subscription']) - storage_account_keys = storage_client.storage_accounts.list_keys(parsed_storage_account['resource_group'], storage_account_name) + storage_account_keys = storage_client.storage_accounts.list_keys(parsed_storage_account['resource_group'], + storage_account_name) kwargs = { 'account_name': storage_account_name, 'account_key': storage_account_keys.keys[0].value @@ -1155,7 +1172,8 @@ def aks_kollect(cmd, client, resource_group_name, name, print() print('This will deploy a daemon set to your cluster to collect logs and diagnostic information and ' - f'save them to the storage account {colorama.Style.BRIGHT}{colorama.Fore.GREEN}{storage_account_name}{colorama.Style.RESET_ALL} as ' + f'save them to the storage account ' + f'{colorama.Style.BRIGHT}{colorama.Fore.GREEN}{storage_account_name}{colorama.Style.RESET_ALL} as ' f'outlined in {format_hyperlink("http://aka.ms/AKSPeriscope")}.') print() print('If you share access to that storage account to Azure support, you consent to the terms outlined' @@ -1173,9 +1191,12 @@ def aks_kollect(cmd, client, resource_group_name, name, print("Starts collecting diag info for cluster %s " % name) sas_token = sas_token.strip('?') - deployment_yaml = urlopen("https://raw.githubusercontent.com/Azure/aks-periscope/v0.2/deployment/aks-periscope.yaml").read().decode() - deployment_yaml = deployment_yaml.replace("# ", (base64.b64encode(bytes(storage_account_name, 'ascii'))).decode('ascii')) - deployment_yaml = deployment_yaml.replace("# ", (base64.b64encode(bytes("?" + sas_token, 'ascii'))).decode('ascii')) + deployment_yaml = urlopen( + "https://raw.githubusercontent.com/Azure/aks-periscope/v0.2/deployment/aks-periscope.yaml").read().decode() + deployment_yaml = deployment_yaml.replace("# ", + (base64.b64encode(bytes(storage_account_name, 'ascii'))).decode('ascii')) + deployment_yaml = deployment_yaml.replace("# ", + (base64.b64encode(bytes("?" + sas_token, 'ascii'))).decode('ascii')) yaml_lines = deployment_yaml.splitlines() for index, line in enumerate(yaml_lines): @@ -1197,23 +1218,35 @@ def aks_kollect(cmd, client, resource_group_name, name, print() print("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"], stderr=subprocess.STDOUT) + subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", + "serviceaccount,configmap,daemonset,secret", + "--all", "-n", "aks-periscope", "--ignore-not-found"], + stderr=subprocess.STDOUT) - subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "ClusterRoleBinding", - "aks-periscope-role-binding", "--ignore-not-found"], stderr=subprocess.STDOUT) + subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", + "ClusterRoleBinding", + "aks-periscope-role-binding", "--ignore-not-found"], + stderr=subprocess.STDOUT) - subprocess.call(["kubectl", "--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", + "ClusterRoleBinding", + "aks-periscope-role-binding-view", "--ignore-not-found"], + stderr=subprocess.STDOUT) - subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "ClusterRole", - "aks-periscope-role", "--ignore-not-found"], stderr=subprocess.STDOUT) + subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", + "ClusterRole", + "aks-periscope-role", "--ignore-not-found"], + stderr=subprocess.STDOUT) - subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "--all", - "apd", "-n", "aks-periscope", "--ignore-not-found"], stderr=subprocess.DEVNULL) + subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", + "--all", + "apd", "-n", "aks-periscope", "--ignore-not-found"], + stderr=subprocess.DEVNULL) - subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", "CustomResourceDefinition", - "diagnostics.aks-periscope.azure.github.com", "--ignore-not-found"], stderr=subprocess.STDOUT) + subprocess.call(["kubectl", "--kubeconfig", temp_kubeconfig_path, "delete", + "CustomResourceDefinition", + "diagnostics.aks-periscope.azure.github.com", "--ignore-not-found"], + stderr=subprocess.STDOUT) print() print("Deploying aks-periscope") @@ -1227,18 +1260,21 @@ def aks_kollect(cmd, client, resource_group_name, name, print() normalized_fqdn = mc.fqdn.replace('.', '-') token_in_storage_account_url = readonly_sas_token if readonly_sas_token is not None else sas_token - log_storage_account_url = f"https://{storage_account_name}.blob.core.windows.net/{normalized_fqdn}?{token_in_storage_account_url}" + log_storage_account_url = f"https://{storage_account_name}.blob.core.windows.net/" \ + f"{normalized_fqdn}?{token_in_storage_account_url}" print(f'{colorama.Fore.GREEN}Your logs are being uploaded to storage account {format_bright(storage_account_name)}') print() - print(f'You can download Azure Stroage Explorer here {format_hyperlink("https://azure.microsoft.com/en-us/features/storage-explorer/")}' + print(f'You can download Azure Stroage Explorer here ' + f'{format_hyperlink("https://azure.microsoft.com/en-us/features/storage-explorer/")}' f' to check the logs by adding the storage account using the following URL:') print(f'{format_hyperlink(log_storage_account_url)}') print() if not prompt_y_n('Do you want to see analysis results now?', default="n"): - print(f"You can run 'az aks kanalyze -g {resource_group_name} -n {name}' anytime to check the analysis results.") + print(f"You can run 'az aks kanalyze -g {resource_group_name} -n {name}' " + f"anytime to check the analysis results.") return else: display_diagnostics_report(temp_kubeconfig_path) @@ -1257,11 +1293,18 @@ def aks_kanalyze(cmd, client, resource_group_name, name): display_diagnostics_report(temp_kubeconfig_path) -def aks_scale(cmd, client, resource_group_name, name, node_count, nodepool_name="", no_wait=False): +def aks_scale(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + name, + node_count, + nodepool_name="", + no_wait=False): instance = client.get(resource_group_name, name) if len(instance.agent_pool_profiles) > 1 and nodepool_name == "": - raise CLIError('There are more than one node pool in the cluster. Please specify nodepool name or use az aks nodepool command to scale node pool') + raise CLIError('There are more than one node pool in the cluster. ' + 'Please specify nodepool name or use az aks nodepool command to scale node pool') if node_count == 0: raise CLIError("Can't scale down to 0 nodes.") @@ -1275,8 +1318,14 @@ def aks_scale(cmd, client, resource_group_name, name, node_count, nodepool_name= raise CLIError('The nodepool "{}" was not found.'.format(nodepool_name)) -def aks_upgrade(cmd, client, resource_group_name, name, kubernetes_version, - control_plane_only=False, no_wait=False, **kwargs): # pylint: disable=unused-argument +def aks_upgrade(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + name, + kubernetes_version, + control_plane_only=False, + no_wait=False, + **kwargs): # pylint: disable=unused-argument instance = client.get(resource_group_name, name) if instance.kubernetes_version == kubernetes_version: @@ -1697,7 +1746,7 @@ def _create_client_secret(): def _ensure_aks_acr(cli_ctx, client_id, acr_name_or_id, - subscription_id, + subscription_id, # pylint: disable=unused-argument detach=False): from msrestazure.tools import is_valid_resource_id, parse_resource_id # Check if the ACR exists by resource ID. @@ -1746,16 +1795,27 @@ def _ensure_aks_acr_role_assignment(cli_ctx, return -def aks_agentpool_show(cmd, client, resource_group_name, cluster_name, nodepool_name): +def aks_agentpool_show(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name, + nodepool_name): instance = client.get(resource_group_name, cluster_name, nodepool_name) return instance -def aks_agentpool_list(cmd, client, resource_group_name, cluster_name): +def aks_agentpool_list(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name): return client.list(resource_group_name, cluster_name) -def aks_agentpool_add(cmd, client, resource_group_name, cluster_name, nodepool_name, +def aks_agentpool_add(cmd, # pylint: disable=unused-argument,too-many-locals + client, + resource_group_name, + cluster_name, + nodepool_name, kubernetes_version=None, node_zones=None, node_vm_size=None, @@ -1838,7 +1898,10 @@ def aks_agentpool_add(cmd, client, resource_group_name, cluster_name, nodepool_n return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, cluster_name, nodepool_name, agent_pool) -def aks_agentpool_scale(cmd, client, resource_group_name, cluster_name, +def aks_agentpool_scale(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name, nodepool_name, node_count=3, no_wait=False): @@ -1852,7 +1915,10 @@ def aks_agentpool_scale(cmd, client, resource_group_name, cluster_name, return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, cluster_name, nodepool_name, instance) -def aks_agentpool_upgrade(cmd, client, resource_group_name, cluster_name, +def aks_agentpool_upgrade(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name, kubernetes_version, nodepool_name, no_wait=False): @@ -1862,7 +1928,11 @@ def aks_agentpool_upgrade(cmd, client, resource_group_name, cluster_name, return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, cluster_name, nodepool_name, instance) -def aks_agentpool_update(cmd, client, resource_group_name, cluster_name, nodepool_name, +def aks_agentpool_update(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name, + nodepool_name, enable_cluster_autoscaler=False, disable_cluster_autoscaler=False, update_cluster_autoscaler=False, @@ -1917,7 +1987,10 @@ def aks_agentpool_update(cmd, client, resource_group_name, cluster_name, nodepoo return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, cluster_name, nodepool_name, instance) -def aks_agentpool_delete(cmd, client, resource_group_name, cluster_name, +def aks_agentpool_delete(cmd, # pylint: disable=unused-argument + client, + resource_group_name, + cluster_name, nodepool_name, no_wait=False): agentpool_exists = False @@ -1981,12 +2054,19 @@ def aks_enable_addons(cmd, client, resource_group_name, name, addons, workspace_ return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, name, instance) -def aks_rotate_certs(cmd, client, resource_group_name, name, no_wait=True): +def aks_rotate_certs(cmd, client, resource_group_name, name, no_wait=True): # pylint: disable=unused-argument return sdk_no_wait(no_wait, client.rotate_cluster_certificates, resource_group_name, name) -def _update_addons(cmd, instance, subscription_id, resource_group_name, addons, enable, workspace_resource_id=None, - subnet_name=None, no_wait=False): +def _update_addons(cmd, + instance, + subscription_id, + resource_group_name, + addons, + enable, + workspace_resource_id=None, + subnet_name=None, + no_wait=False): # pylint: disable=unused-argument # parse the comma-separated addons argument addon_args = addons.split(',') @@ -2049,7 +2129,7 @@ def _update_addons(cmd, instance, subscription_id, resource_group_name, addons, return instance -def aks_get_versions(cmd, client, location): +def aks_get_versions(cmd, client, location): # pylint: disable=unused-argument return client.list_orchestrators(location, resource_type='managedClusters') @@ -2238,11 +2318,13 @@ def get_storage_account_from_diag_settings(cli_ctx, resource_group_name, name): return None -def display_diagnostics_report(temp_kubeconfig_path): +def display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-many-statements if not which('kubectl'): raise CLIError('Can not find kubectl executable in PATH') - nodes = subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "node", "--no-headers"], universal_newlines=True) + nodes = subprocess.check_output( + ["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "node", "--no-headers"], + universal_newlines=True) logger.debug(nodes) node_lines = nodes.splitlines() ready_nodes = {} @@ -2250,11 +2332,11 @@ def display_diagnostics_report(temp_kubeconfig_path): columns = node_line.split() logger.debug(node_line) if columns[1] != "Ready": - logger.warning("Node {} is not Ready. Current state is: {}.".format(columns[0], columns[1])) + logger.warning("Node %s is not Ready. Current state is: %s.", columns[0], columns[1]) else: ready_nodes[columns[0]] = False - logger.debug('There are {} ready nodes in the cluster'.format(len(ready_nodes))) + logger.debug('There are %s ready nodes in the cluster', str(len(ready_nodes))) if not ready_nodes: logger.warning('No nodes are ready in the current cluster. Diagnostics info might not be available.') @@ -2266,12 +2348,17 @@ def display_diagnostics_report(temp_kubeconfig_path): max_retry = 10 for retry in range(0, max_retry): if not apds_created: - apd = subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "apd", "-n", "aks-periscope", "--no-headers"], universal_newlines=True) + apd = subprocess.check_output( + ["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "apd", "-n", "aks-periscope", "--no-headers"], + universal_newlines=True + ) apd_lines = apd.splitlines() if apd_lines and 'No resources found' in apd_lines[0]: apd_lines.pop(0) - print("Got {} diagnostic results for {} ready nodes{}\r".format(len(apd_lines), len(ready_nodes), '.' * retry), end='') + print("Got {} diagnostic results for {} ready nodes{}\r".format(len(apd_lines), + len(ready_nodes), + '.' * retry), end='') if len(apd_lines) < len(ready_nodes): time.sleep(3) else: @@ -2283,13 +2370,22 @@ def display_diagnostics_report(temp_kubeconfig_path): continue apdName = "aks-periscope-diagnostic-" + node_name try: - network_config = subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "apd", apdName, "-n", "aks-periscope", "-o=jsonpath={.spec.networkconfig}"], universal_newlines=True) - logger.debug('Dns status for node {} is {}'.format(node_name, network_config)) - network_status = subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "get", "apd", apdName, "-n", "aks-periscope", "-o=jsonpath={.spec.networkoutbound}"], universal_newlines=True) - logger.debug('Network status for node {} is {}'.format(node_name, network_status)) + network_config = subprocess.check_output( + ["kubectl", "--kubeconfig", temp_kubeconfig_path, + "get", "apd", apdName, "-n", + "aks-periscope", "-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}"], + universal_newlines=True) + logger.debug('Network status for node %s is %s', node_name, network_status) if not network_config or not network_status: - print("The diagnostics information for node {} is not ready yet. Will try again in 10 seconds.".format(node_name)) + print("The diagnostics information for node {} is not ready yet. " + "Will try again in 10 seconds.".format(node_name)) time.sleep(10) break @@ -2307,14 +2403,16 @@ def display_diagnostics_report(temp_kubeconfig_path): print(tabulate(network_config_array, headers="keys", tablefmt='simple')) print() else: - logger.warning("Could not get network config. Please run 'az aks kanalyze' command later to get the analysis results.") + logger.warning("Could not get network config. " + "Please run 'az aks kanalyze' command later to get the analysis results.") if network_status_array: print("Below are the network connectivity results for each node:") print() print(tabulate(network_status_array, headers="keys", tablefmt='simple')) else: - logger.warning("Could not get networking status. Please run 'az aks kanalyze' command later to get the analysis results.") + logger.warning("Could not get networking status. " + "Please run 'az aks kanalyze' command later to get the analysis results.") def format_diag_status(diag_status): diff --git a/src/application-insights/azext_applicationinsights/commands.py b/src/application-insights/azext_applicationinsights/commands.py index 51919463287..f1fb1bdb0d5 100644 --- a/src/application-insights/azext_applicationinsights/commands.py +++ b/src/application-insights/azext_applicationinsights/commands.py @@ -5,6 +5,8 @@ # pylint: disable=line-too-long +from azure.cli.core.commands import CliCommandType + from azext_applicationinsights._client_factory import ( cf_events, cf_metrics, @@ -13,8 +15,6 @@ cf_api_key ) -from azure.cli.core.commands import CliCommandType - def load_command_table(self, _): diff --git a/src/find/azext_find/custom.py b/src/find/azext_find/custom.py index 4e167293b79..442237655b3 100644 --- a/src/find/azext_find/custom.py +++ b/src/find/azext_find/custom.py @@ -29,7 +29,8 @@ def process_query(cli_term): response = call_aladdin_service(cli_term) if response.status_code != 200: - logger.error('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content)) + err_msg = '[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content) + logger.error(err_msg) else: if (platform.system() == 'Windows' and should_enable_styling()): colorama.init(convert=True) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index 00b4666028d..e0f92a5aa15 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -15,6 +15,13 @@ from threading import Thread from six.moves import configparser +from knack.log import get_logger +from knack.util import CLIError +from azure.cli.core.commands.client_factory import ENV_ADDITIONAL_USER_AGENT +from azure.cli.core._profile import _SUBSCRIPTION_NAME, Profile +from azure.cli.core._session import ACCOUNT, CONFIG, SESSION +from azure.cli.core.api import get_config_dir +from azure.cli.core.util import handle_exception # pylint: disable=import-error import jmespath @@ -28,15 +35,6 @@ from prompt_toolkit.shortcuts import create_eventloop # pylint: enable=import-error -from azure.cli.core.commands.client_factory import ENV_ADDITIONAL_USER_AGENT -from azure.cli.core._profile import _SUBSCRIPTION_NAME, Profile -from azure.cli.core._session import ACCOUNT, CONFIG, SESSION -from azure.cli.core.api import get_config_dir -from azure.cli.core.util import handle_exception - -from knack.log import get_logger -from knack.util import CLIError - from . import VERSION from .az_completer import AzCompleter from .az_lexer import get_az_lexer, ExampleLexer, ToolbarLexer diff --git a/src/interactive/azext_interactive/azclishell/az_completer.py b/src/interactive/azext_interactive/azclishell/az_completer.py index 04128f6b95b..5bd3a1de94a 100644 --- a/src/interactive/azext_interactive/azclishell/az_completer.py +++ b/src/interactive/azext_interactive/azclishell/az_completer.py @@ -6,12 +6,15 @@ from __future__ import absolute_import, division, print_function, unicode_literals import os -from prompt_toolkit.completion import Completer, Completion # pylint: disable=import-error + from azure.cli.core.parser import AzCliCommandParser from azure.cli.core.commands.events import ( EVENT_INTERACTIVE_PRE_COMPLETER_TEXT_PARSING, EVENT_INTERACTIVE_POST_SUB_TREE_CREATE ) + +from prompt_toolkit.completion import Completer, Completion # pylint: disable=import-error + from . import configuration from .argfinder import ArgsFinder from .util import parse_quotes diff --git a/src/interactive/azext_interactive/azclishell/color_styles.py b/src/interactive/azext_interactive/azclishell/color_styles.py index b3ca814c650..893dde2bb5d 100644 --- a/src/interactive/azext_interactive/azclishell/color_styles.py +++ b/src/interactive/azext_interactive/azclishell/color_styles.py @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------------------------- import platform -from prompt_toolkit.styles import style_from_dict # pylint: disable=import-error from pygments.token import Token # pylint: disable=import-error +from prompt_toolkit.styles import style_from_dict # pylint: disable=import-error def color_mapping(curr_completion, completion, prompt, command, subcommand, diff --git a/src/interactive/azext_interactive/azclishell/configuration.py b/src/interactive/azext_interactive/azclishell/configuration.py index f70398596ac..f2a73ad6508 100644 --- a/src/interactive/azext_interactive/azclishell/configuration.py +++ b/src/interactive/azext_interactive/azclishell/configuration.py @@ -7,9 +7,11 @@ import os from six.moves import configparser -from prompt_toolkit import prompt # pylint: disable=import-error + from azure.cli.core._help import PRIVACY_STATEMENT +from prompt_toolkit import prompt # pylint: disable=import-error + SELECT_SYMBOL = { 'outside': '#', diff --git a/src/interactive/azext_interactive/azclishell/layout.py b/src/interactive/azext_interactive/azclishell/layout.py index ac607823e98..d449292d89a 100644 --- a/src/interactive/azext_interactive/azclishell/layout.py +++ b/src/interactive/azext_interactive/azclishell/layout.py @@ -4,6 +4,8 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=import-error +from pygments.token import Token +from pygments.lexer import Lexer as PygLex from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER from prompt_toolkit.filters import Condition, Always, IsDone, HasFocus, RendererHeightIsKnown from prompt_toolkit.layout.containers import VSplit, HSplit, \ @@ -18,9 +20,6 @@ from prompt_toolkit.layout.prompt import DefaultPrompt from prompt_toolkit.layout.screen import Char -from pygments.token import Token -from pygments.lexer import Lexer as PygLex -# pylint: enable=import-error from .progress import get_progress_message, get_done diff --git a/src/interactive/azext_interactive/azclishell/progress.py b/src/interactive/azext_interactive/azclishell/progress.py index dd7c81b636b..901c91dafa1 100644 --- a/src/interactive/azext_interactive/azclishell/progress.py +++ b/src/interactive/azext_interactive/azclishell/progress.py @@ -5,9 +5,10 @@ from random import randint from time import sleep +from azure.cli.core.commands.progress import ProgressViewBase + from prompt_toolkit.document import Document # pylint: disable=import-error -from azure.cli.core.commands.progress import ProgressViewBase from .util import get_window_dim diff --git a/src/mesh/azext_mesh/custom.py b/src/mesh/azext_mesh/custom.py index 327b24857ba..f20395c8551 100644 --- a/src/mesh/azext_mesh/custom.py +++ b/src/mesh/azext_mesh/custom.py @@ -237,7 +237,7 @@ def _invoke_mergeutil(input_yaml_files=None, parameters=None): def _generate_arm_template_core(input_yaml_files=None, parameters=None): output_file_path = _invoke_mergeutil(input_yaml_files, parameters) - logger.warning("Generated ARM template file at {0}.".format(output_file_path)) + logger.warning("Generated ARM template file at %s.", output_file_path) def _deploy_arm_template_core(cli_ctx, resource_group_name, # pylint: disable=too-many-arguments @@ -279,7 +279,7 @@ def _deploy_arm_template_core(cli_ctx, resource_group_name, # pylint: disable=t logger.warning("Deploying . . .") logger.warning("You can get the state of the deployment with the cmd") - logger.warning("az group deployment show --name {0} --resource-group {1}".format(deployment_name, resource_group_name)) + logger.warning("az group deployment show --name %s --resource-group %s", deployment_name, resource_group_name) if validate_only: return sdk_no_wait(no_wait, smc.deployments.validate, resource_group_name, deployment_name, properties) diff --git a/src/resource-graph/azext_resourcegraph/custom.py b/src/resource-graph/azext_resourcegraph/custom.py index 215ac7a4837..8cde8341ffb 100644 --- a/src/resource-graph/azext_resourcegraph/custom.py +++ b/src/resource-graph/azext_resourcegraph/custom.py @@ -52,7 +52,7 @@ def execute_query(client, graph_query, first, skip, subscriptions, include): full_query = _get_extension() + "| " + graph_query except Exception as e: - __logger.warning("Failed to include displayNames to result. Error: " + str(e)) + __logger.warning("Failed to include displayNames to result. Error: %s", e) try: result_truncated = False diff --git a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_paged_query.yaml b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_paged_query.yaml index 8549e845214..3c707752b0f 100644 --- a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_paged_query.yaml +++ b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_paged_query.yaml @@ -1,67 +1,70 @@ interactions: - request: - body: '{"subscriptions": ["00000000-0000-0000-0000-000000000000"], - "query": "project id", "options": {"$top": 2, "$skip": 2}}' + body: '{"subscriptions": ["a18897a6-7e44-457d-9260-f2854c0aca42", "e01de573-132a-42ac-9ee2-f9dea9dd2717", + "d21a0e9f-5e29-4b39-8ba5-0e189bc5fe2d", "c59ea945-6d69-43cb-8cf5-7674fc245c37", + "d03b04c7-d1d4-467b-aaaa-87b6fcb38b38", "26b9b438-7fe8-482f-b732-ea99c70f2abb", + "8bc2f89b-c4f6-4559-ad6a-4f2cfa6ccc49", "eb87f285-893a-4f0f-8c55-7b4f67b1d097", + "52a442a2-31e9-42f9-8e3e-4b27dbf82673", "bead59b7-f469-4601-803a-790729c5213d", + "33b1bf3d-53dc-432d-ac1c-ae964ceb1c9b", "979523fb-a19c-4bb0-a8ee-cef29597b0a4", + "bd62906c-0a81-43c3-a2f8-126e4cf66ada", "ac073789-bf4e-4438-a70d-fe98276e2771", + "00c06639-6ee4-454e-8058-8d8b1703bd87", "ae4fd9c1-f57f-4077-8cb5-e9c0a1bb8796", + "6b085460-5f21-477e-ba44-1035046e9101", "0b1f6471-1bf0-4dda-aec3-cb9272f09590"], + "query": "project id", "options": {"$top": 3, "$skip": 2, "resultFormat": "objectArray"}}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['958'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - graph query + Connection: + - keep-alive + Content-Length: + - '829' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -q --first --skip + User-Agent: + - python/3.6.8 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-resourcegraph/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview + uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2019-04-01 response: - body: {string: '{"totalRecords":9969,"count":2,"data":{"columns":[{"name":"id","type":"string"}],"rows":[["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AaaaaAaaaaaaaaAaaaaAaaaaaaaaaaa-AAA-a/providers/Microsoft.EventHub/namespaces/eventhub-local-aaaaaaa"],["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AaaaaAaaaaaaaaAaaaaAaaaaaaaaaaa-AAA-a/providers/Microsoft.Network/loadBalancers/LB-aaa-aaa-aaa-aa-a-aa"]]},"facets":[],"resultTruncated":"false","$skipToken":"82aw3vQlArEastJ24LABY8oPgQLesIyAyzYs2g6/aOOOmJHSYFj39fODurJV5e2tTFFebWcfxn7n5edicA8u6HgSJe1GCEk5HjxwLkeJiye2LVZDC7TaValkJbsk9JqY4yv5c7iRiLqgO34RbHEeVfLJpa56u4RZu0K+GpQvnBRPyAhy3KbwhZWpU5Nnqnud2whGb5WKdlL8xF7wnQaUnUN2lns8WwqwM4rc0VK4BbQt/WfWWcYJivSAyB3m4Z5g73df1KiU4C+K8auvUMpLPYVxxnKC/YZz42YslVAWXXUmuGOaM2SfLHRO6o4O9DgXlUgYjeFWqIbAkmMiVEqU"}'} + body: + string: '{"totalRecords":353,"count":3,"data":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/1210test/providers/Microsoft.Compute/virtualMachines/clivm/extensions/DependencyAgentLinux"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/1210test/providers/Microsoft.Compute/virtualMachines/clivm/extensions/OMSExtension"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/1210test/providers/Microsoft.Insights/metricalerts/1211mytest"}],"facets":[],"resultTruncated":"false","$skipToken":"ew0KICAiJGlkIjogIjEiLA0KICAiTWF4Um93cyI6IDMsDQogICJSb3dzVG9Ta2lwIjogNSwNCiAgIkt1c3RvQ2x1c3RlclVybCI6ICJodHRwczovL2dvdi1hcnQtZXVzLXNhaWxmaXNoLW9uZS5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIg0KfQ=="}' headers: - cache-control: [no-cache] - content-length: ['773'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:34 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1199'] - status: {code: 200, message: OK} -- request: - body: '{"subscriptions": ["00000000-0000-0000-0000-000000000000"], - "query": "project id", "options": {"$skipToken": "82aw3vQlArEastJ24LABY8oPgQLesIyAyzYs2g6/aOOOmJHSYFj39fODurJV5e2tTFFebWcfxn7n5edicA8u6HgSJe1GCEk5HjxwLkeJiye2LVZDC7TaValkJbsk9JqY4yv5c7iRiLqgO34RbHEeVfLJpa56u4RZu0K+GpQvnBRPyAhy3KbwhZWpU5Nnqnud2whGb5WKdlL8xF7wnQaUnUN2lns8WwqwM4rc0VK4BbQt/WfWWcYJivSAyB3m4Z5g73df1KiU4C+K8auvUMpLPYVxxnKC/YZz42YslVAWXXUmuGOaM2SfLHRO6o4O9DgXlUgYjeFWqIbAkmMiVEqU", - "$top": 1, "$skip": 4}}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['1256'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] - method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview - response: - body: {string: '{"totalRecords":9969,"count":1,"data":{"columns":[{"name":"id","type":"string"}],"rows":[["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/AaaaaAaaaaaaaaAaaaaAaaaaaaaaaaa-AAA-a/providers/Microsoft.Network/networkSecurityGroups/nsgSubnet-0"]]},"facets":[],"resultTruncated":"false","$skipToken":"ceXHDV/5yajn1stYtSCyQ32ULLF0jGv9oazG14qvdgwdAQNDUPHjt6MIlJZ2Y/K8z7fb+qo9wguegf8QYW0c7rqwtXUghJvKkPBENcn1O17nQxtjXeq6s8sD64D8t5P9NIHntl70D95yuVUjHF6/dsvVK33wKyvORwPTCbZrSj+pfz2yd5spa93izzOu06PcyFvcvCJAzZ5scImnVDqS700hR63izVwyETJtQluoqSPYkhxAOVk/+ThWlN0DKy9OfUE34M9PZSQz2QTWXKpUK1+okRfH/B2RVdXro60ZnNMrdPtglA5w7oEs5Ivq20IE4RtPfg97UEbkfyMP9huC="}'} - headers: - cache-control: [no-cache] - content-length: ['597'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:33 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1197'] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '745' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 12 Dec 2019 03:02:52 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Kestrel + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-tenant-resource-requests: + - '14' + x-ms-user-quota-remaining: + - '14' + x-ms-user-quota-resets-after: + - 00:00:05 + status: + code: 200 + message: OK version: 1 diff --git a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query.yaml b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query.yaml index 3bc0cde4efe..2ffcac7993c 100644 --- a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query.yaml +++ b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query.yaml @@ -1,34 +1,71 @@ interactions: - request: - body: '{"subscriptions": ["00000000-0000-0000-0000-000000000000"], - "query": "project id, tags, properties | limit 2", "options": {"$top": 2, "$skip": 0}}' + body: '{"subscriptions": ["a18897a6-7e44-457d-9260-f2854c0aca42", "e01de573-132a-42ac-9ee2-f9dea9dd2717", + "d21a0e9f-5e29-4b39-8ba5-0e189bc5fe2d", "c59ea945-6d69-43cb-8cf5-7674fc245c37", + "d03b04c7-d1d4-467b-aaaa-87b6fcb38b38", "26b9b438-7fe8-482f-b732-ea99c70f2abb", + "8bc2f89b-c4f6-4559-ad6a-4f2cfa6ccc49", "eb87f285-893a-4f0f-8c55-7b4f67b1d097", + "52a442a2-31e9-42f9-8e3e-4b27dbf82673", "bead59b7-f469-4601-803a-790729c5213d", + "33b1bf3d-53dc-432d-ac1c-ae964ceb1c9b", "979523fb-a19c-4bb0-a8ee-cef29597b0a4", + "bd62906c-0a81-43c3-a2f8-126e4cf66ada", "ac073789-bf4e-4438-a70d-fe98276e2771", + "00c06639-6ee4-454e-8058-8d8b1703bd87", "ae4fd9c1-f57f-4077-8cb5-e9c0a1bb8796", + "6b085460-5f21-477e-ba44-1035046e9101", "0b1f6471-1bf0-4dda-aec3-cb9272f09590"], + "query": "project id, tags, properties | limit 2", "options": {"$top": 100, + "$skip": 0, "resultFormat": "objectArray"}}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['986'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - graph query + Connection: + - keep-alive + Content-Length: + - '859' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -q + User-Agent: + - python/3.6.8 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-resourcegraph/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview + uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2019-04-01 response: - body: {string: '{"totalRecords":2,"count":2,"data":{"columns":[{"name":"id","type":"string"},{"name":"tags","type":"object"},{"name":"properties","type":"object"}],"rows":[["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mms-wcus/providers/Microsoft.Automation/automationAccounts/Automate-1394611-WCUS",{},{"creationTime":"2017-06-01T05:35:53.1000000Z","lastModifiedTime":"2018-08-07T18:40:20.7730000Z","lastModifiedBy":"aaaaa@aaaaaaaaa.com","state":"Ok","RegistrationUrl":"https://aaaa-aaaaaservice-prod-1.azure-automation.net/accounts/b8103983-a1e8-a1e8-a1e8-b8103983b3e9","sku":{"name":"Free","capacity":null,"family":null}}],["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testRG/providers/Microsoft.Network/publicIPAddresses/myPublicIP",{},{"provisioningState":"Succeeded","resourceGuid":"e143e88a-b2df-b2df-b2df-e143e88aef12","publicIPAllocationMethod":"Dynamic","idleTimeoutInMinutes":4,"publicIPAddressVersion":"IPv4","dnsSettings":{"domainNameLabel":"testuser000","fqdn":"testuser000.eastus.cloudapp.azure.com"},"ipConfiguration":{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testRG/providers/Microsoft.Network/networkInterfaces/myVMNic/ipConfigurations/ipconfig1"},"ipTags":[],"ipAddress":"99.999.99.99"}]]},"facets":[],"resultTruncated":"false"}'} + body: + string: '{"totalRecords":2,"count":2,"data":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/yugangwbyok10/providers/Microsoft.KeyVault/vaults/yugangwbyok10-kv","tags":{},"properties":{"provisioningState":"Succeeded","sku":{"name":"standard","family":"A"},"tenantId":"54826b22-38d6-4fb2-bad9-b7b93a3e9c5a","enabledForDeployment":false,"accessPolicies":[{"tenantId":"54826b22-38d6-4fb2-bad9-b7b93a3e9c5a","permissions":{"secrets":["get","list","set","delete","backup","restore","recover"],"certificates":["get","list","delete","create","import","update","managecontacts","getissuers","listissuers","setissuers","deleteissuers","manageissuers","recover"],"keys":["get","create","delete","list","update","import","backup","restore","recover"],"storage":["get","list","delete","set","update","regeneratekey","setsas","listsas","getsas","deletesas"]},"objectId":"89ed5be8-ff97-41b5-ab11-055e1e3cc34b"},{"tenantId":"54826b22-38d6-4fb2-bad9-b7b93a3e9c5a","permissions":{"keys":["get","recover","unwrapKey","wrapKey"]},"objectId":"088d0f75-90eb-4619-83c2-c0f6c3b1f6d7"}],"vaultUri":"https://yugangwbyok10-kv.vault.azure.net/","enableSoftDelete":true,"enablePurgeProtection":true}},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/yugangwbyok10/providers/Microsoft.ManagedIdentity/userAssignedIdentities/yugangwbyok10-mi","tags":{},"properties":{"tenantId":"54826b22-38d6-4fb2-bad9-b7b93a3e9c5a","principalId":"088d0f75-90eb-4619-83c2-c0f6c3b1f6d7","clientId":"36ddc83f-df48-415e-b17a-553a4392f9c0"}}],"facets":[],"resultTruncated":"false"}' headers: - cache-control: [no-cache] - content-length: ['1309'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:35 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1198'] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '1573' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 12 Dec 2019 03:02:52 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Kestrel + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-tenant-resource-requests: + - '12' + x-ms-user-quota-remaining: + - '12' + x-ms-user-quota-resets-after: + - 00:00:05 + status: + code: 200 + message: OK version: 1 diff --git a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query_error.yaml b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query_error.yaml index 93ebad483cc..9077485a8fd 100644 --- a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query_error.yaml +++ b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_query_error.yaml @@ -1,33 +1,71 @@ interactions: - request: - body: '{"subscriptions": ["00000000-0000-0000-0000-000000000000"], - "query": "where where", "options": {"$top": 2, "$skip": 0}}' + body: '{"subscriptions": ["a18897a6-7e44-457d-9260-f2854c0aca42", "e01de573-132a-42ac-9ee2-f9dea9dd2717", + "d21a0e9f-5e29-4b39-8ba5-0e189bc5fe2d", "c59ea945-6d69-43cb-8cf5-7674fc245c37", + "d03b04c7-d1d4-467b-aaaa-87b6fcb38b38", "26b9b438-7fe8-482f-b732-ea99c70f2abb", + "8bc2f89b-c4f6-4559-ad6a-4f2cfa6ccc49", "eb87f285-893a-4f0f-8c55-7b4f67b1d097", + "52a442a2-31e9-42f9-8e3e-4b27dbf82673", "bead59b7-f469-4601-803a-790729c5213d", + "33b1bf3d-53dc-432d-ac1c-ae964ceb1c9b", "979523fb-a19c-4bb0-a8ee-cef29597b0a4", + "bd62906c-0a81-43c3-a2f8-126e4cf66ada", "ac073789-bf4e-4438-a70d-fe98276e2771", + "00c06639-6ee4-454e-8058-8d8b1703bd87", "ae4fd9c1-f57f-4077-8cb5-e9c0a1bb8796", + "6b085460-5f21-477e-ba44-1035046e9101", "0b1f6471-1bf0-4dda-aec3-cb9272f09590"], + "query": "where where", "options": {"$top": 100, "$skip": 0, "resultFormat": + "objectArray"}}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['959'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - graph query + Connection: + - keep-alive + Content-Length: + - '832' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -q + User-Agent: + - python/3.6.8 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-resourcegraph/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview + uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2019-04-01 response: - body: {string: "{\"error\":{\"code\":\"InvalidQuery\",\"message\":\"Query validation - error\",\"details\":[{\"code\":\"ParserFailure\",\"message\":\"Parser failure\",\"line\":1,\"characterPositionInLine\":11,\"token\":\"\",\"expectedToken\":\"\u0178\"}]}}"} + body: + string: "{\"error\":{\"code\":\"BadRequest\",\"message\":\"Please provide below + info when asking for support: timestamp = 2019-12-12T03:02:52.2568093Z, correlationId + = dcfb51de-e1d1-44cc-ade0-c7b186674eac.\",\"details\":[{\"code\":\"InvalidQuery\",\"message\":\"Query + is invalid. Please refer to the documentation for the Azure Resource Graph + service and fix the error before retrying.\"},{\"code\":\"ParserFailure\",\"message\":\"ParserFailure\",\"line\":1,\"characterPositionInLine\":11,\"token\":\"\",\"expectedToken\":\"\u0179\"}]}}" headers: - cache-control: [no-cache] - content-length: ['207'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:36 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1199'] - status: {code: 400, message: Bad Request} + cache-control: + - no-cache + content-length: + - '488' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 12 Dec 2019 03:02:51 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Kestrel + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-tenant-resource-requests: + - '13' + x-ms-user-quota-remaining: + - '13' + x-ms-user-quota-resets-after: + - 00:00:05 + status: + code: 400 + message: Bad Request version: 1 diff --git a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_subscriptions.yaml b/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_subscriptions.yaml deleted file mode 100644 index 7282766444e..00000000000 --- a/src/resource-graph/azext_resourcegraph/tests/latest/recordings/test_subscriptions.yaml +++ /dev/null @@ -1,68 +0,0 @@ -interactions: -- request: - body: '{"subscriptions": ["00000000-0000-0000-0000-000000000000"], - "query": "distinct subscriptionId | order by subscriptionId asc", "options": - {"$top": 2, "$skip": 0}}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['1002'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] - method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview - response: - body: {string: '{"totalRecords":1,"count":1,"data":{"columns":[{"name":"subscriptionId","type":"string"}],"rows":[["00000000-0000-0000-0000-000000000000"]]},"facets":[],"resultTruncated":"false"}'} - headers: - cache-control: [no-cache] - content-length: ['220'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:37 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1198'] - status: {code: 200, message: OK} -- request: - body: '{"subscriptions": ["11111111-1111-1111-1111-111111111111", "22222222-2222-2222-2222-222222222222"], - "query": "distinct subscriptionId | order by subscriptionId asc", "options": - {"$top": 2, "$skip": 0}}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - CommandName: [graph query] - Connection: [keep-alive] - Content-Length: ['201'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.3 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.5 - msrest_azure/0.4.34 azure-mgmt-resourcegraph/0.6.0 Azure-SDK-For-Python - AZURECLI/2.0.46] - accept-language: [en-US] - method: POST - uri: https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2018-09-01-preview - response: - body: {string: '{"totalRecords":2,"count":2,"data":{"columns":[{"name":"subscriptionId","type":"string"}],"rows":[["11111111-1111-1111-1111-111111111111"],["22222222-2222-2222-2222-222222222222"]]},"facets":[],"resultTruncated":"false"}'} - headers: - cache-control: [no-cache] - content-length: ['220'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 11 Sep 2018 18:28:37 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-tenant-writes: ['1199'] - status: {code: 200, message: OK} -version: 1 diff --git a/src/resource-graph/azext_resourcegraph/tests/latest/test_resourcegraph_commands.py b/src/resource-graph/azext_resourcegraph/tests/latest/test_resourcegraph_commands.py index 27cc8bac181..38a61755aec 100644 --- a/src/resource-graph/azext_resourcegraph/tests/latest/test_resourcegraph_commands.py +++ b/src/resource-graph/azext_resourcegraph/tests/latest/test_resourcegraph_commands.py @@ -31,7 +31,6 @@ def test_query(self): self.assertIsInstance(query_response[1]['id'], string_types) self.assertIsInstance(query_response[1]['tags'], dict) self.assertIsInstance(query_response[1]['properties'], dict) - self.assertTrue(len(query_response[1]['properties']) > 3) def test_paged_query(self): # Page size was artificially set to 2 rows @@ -57,22 +56,6 @@ def test_paged_query(self): self.assertTrue(len(query_response[1]['id']) > 0) self.assertTrue(len(query_response[2]['id']) > 0) - def test_subscriptions(self): - test_sub_id1 = '11111111-1111-1111-1111-111111111111' - test_sub_id2 = '22222222-2222-2222-2222-222222222222' - command_no_subs = 'az graph query -q "distinct subscriptionId | order by subscriptionId asc"' - command_with_subs = command_no_subs + ' --subscriptions {} {}'.format(test_sub_id1, test_sub_id2) - - query_response_no_subs = self.cmd(command_no_subs).get_output_in_json() - query_response_with_subs = self.cmd(command_with_subs).get_output_in_json() - - self.assertTrue(len(query_response_no_subs) == 1) - self.assertEqual(query_response_no_subs[0]['subscriptionId'], MOCKED_SUBSCRIPTION_ID) - - self.assertTrue(len(query_response_with_subs) == 2) - self.assertEqual(query_response_with_subs[0]['subscriptionId'], test_sub_id1) - self.assertEqual(query_response_with_subs[1]['subscriptionId'], test_sub_id2) - def test_query_error(self): command = 'az graph query -q "where where"' @@ -91,14 +74,14 @@ def test_query_error(self): self.assertIsInstance(error_response['error']['details'], list) self.assertTrue(len(error_response['error']['code']) > 0) self.assertTrue(len(error_response['error']['message']) > 0) - self.assertTrue(len(error_response['error']['details']) == 1) + self.assertTrue(len(error_response['error']['details']) == 2) self.assertIsInstance(error_response['error']['details'][0], dict) - self.assertTrue(len(error_response['error']['details'][0]) == 3) + self.assertTrue(len(error_response['error']['details'][0]) == 2) self.assertIsInstance(error_response['error']['details'][0]['code'], string_types) self.assertIsInstance(error_response['error']['details'][0]['message'], string_types) - self.assertIsInstance(error_response['error']['details'][0]['additionalProperties'], dict) + self.assertIsInstance(error_response['error']['details'][1]['additionalProperties'], dict) self.assertTrue(len(error_response['error']['details'][0]['code']) > 0) self.assertTrue(len(error_response['error']['details'][0]['message']) > 0) - self.assertTrue(len(error_response['error']['details'][0]['additionalProperties']) == 4) + self.assertTrue(len(error_response['error']['details'][1]['additionalProperties']) == 4) diff --git a/src/spring-cloud/azext_spring_cloud/azure_storage_file/sharedaccesssignature.py b/src/spring-cloud/azext_spring_cloud/azure_storage_file/sharedaccesssignature.py index 5c2caf3fe38..67aaa7d191a 100644 --- a/src/spring-cloud/azext_spring_cloud/azure_storage_file/sharedaccesssignature.py +++ b/src/spring-cloud/azext_spring_cloud/azure_storage_file/sharedaccesssignature.py @@ -202,7 +202,7 @@ class _FileSharedAccessHelper(_SharedAccessHelper): def __init__(self): super(_FileSharedAccessHelper, self).__init__() - def add_resource_signature(self, account_name, account_key, path): + def add_resource_signature(self, account_name, account_key, path): # pylint: disable=arguments-differ def get_value_to_append(query): return_value = self.query_dict.get(query) or '' return return_value + '\n' diff --git a/src/webapp/azext_webapp/tunnel.py b/src/webapp/azext_webapp/tunnel.py index 40695e8ed17..895d13874d8 100644 --- a/src/webapp/azext_webapp/tunnel.py +++ b/src/webapp/azext_webapp/tunnel.py @@ -175,7 +175,7 @@ def _listen_to_client(self, client, ws_socket, index): ws_socket.send_binary(responseData) logger.info('Done sending to websocket, index: %s', index) else: - logger.warn('Client disconnected %s', index) + logger.warning('Client disconnected %s', index) client.close() ws_socket.close() break