def call_aladdin_service(query): version = str(parse_version(core_version)) correlation_id = telemetry_core._session.correlation_id # pylint: disable=protected-access subscription_id = telemetry_core._get_azure_subscription_id() # pylint: disable=protected-access # Used for DDOS protection and rate limiting user_id = telemetry_core._get_user_azure_id() # pylint: disable=protected-access hashed_user_id = hashlib.sha256(user_id.encode('utf-8')).hexdigest() context = { "versionNumber": version, } # Only pull in the contextual values if we have consent if telemetry_core.is_telemetry_enabled(): context['correlationId'] = correlation_id if telemetry_core.is_telemetry_enabled() and subscription_id is not None: context['subscriptionId'] = subscription_id api_url = 'https://app.aladdin.microsoft.com/api/v1.0/examples' headers = {'Content-Type': 'application/json', 'X-UserId': hashed_user_id} response = requests.get(api_url, params={ 'query': query, 'clientType': 'AzureCli', 'context': json.dumps(context), 'commandOnly': True, 'numberOfExamples': 5 }, headers=headers) return response
def call_aladdin_service(query): version = str(parse_version(core_version)) correlation_id = telemetry_core._session.correlation_id # pylint: disable=protected-access subscription_id = telemetry_core._get_azure_subscription_id() # pylint: disable=protected-access context = { "versionNumber": version, } # Only pull in the contextual values if we have consent if telemetry_core.is_telemetry_enabled(): context['correlationId'] = correlation_id if telemetry_core.is_telemetry_enabled() and subscription_id is not None: context['subscriptionId'] = subscription_id api_url = 'https://app.aladdin.microsoft.com/api/v1.0/examples' headers = {'Content-Type': 'application/json'} response = requests.get(api_url, params={ 'query': query, 'clientType': 'AzureCli', 'context': json.dumps(context) }, headers=headers) return response
def call_aladdin_service(query): correlation_id = telemetry_core._session.correlation_id # pylint: disable=protected-access subscription_id = telemetry_core._get_azure_subscription_id() # pylint: disable=protected-access version = str(parse_version(core_version)) context = { "correlationId": "", "subscriptionId": "", "versionNumber": version } # Only pull in the other values if we have consent if telemetry_core.is_telemetry_enabled(): context.update(correlationId=correlation_id, subscriptionId=subscription_id) api_url = 'https://app.aladdin.microsoft.com/api/v1.0/examples' headers = {'Content-Type': 'application/json'} response = requests.get(api_url, params={ 'query': query, 'clientType': 'AzureCli', 'context': json.dumps(context), 'commandOnly': True, 'numberOfExamples': 5 }, headers=headers) return response
def get_recommend_from_api(command_list, type, top_num=5, error_info=None): # pylint: disable=unused-argument '''query next command from web api''' import requests url = "https://cli-recommendation.azurewebsites.net/api/RecommendationService" user_id = telemetry._get_user_azure_id() # pylint: disable=protected-access hashed_user_id = hashlib.sha256(user_id.encode('utf-8')).hexdigest() payload = { "command_list": json.dumps(command_list), "type": type, "top_num": top_num, 'error_info': error_info, 'cli_version': version, 'user_id': hashed_user_id } correlation_id = telemetry._session.correlation_id subscription_id = telemetry._get_azure_subscription_id() if telemetry.is_telemetry_enabled(): if correlation_id: payload['correlation_id'] = correlation_id if subscription_id: payload['subscription_id'] = subscription_id response = requests.post(url, json.dumps(payload)) if response.status_code != 200: raise RecommendationError( "Failed to connect to '{}' with status code '{}' and reason '{}'". format(url, response.status_code, response.reason)) recommends = [] if 'data' in response.json(): recommends = response.json()['data'] return recommends
def test_cloud_forbid_telemetry(self): from unittest import mock from azure.cli.core import telemetry from azure.cli.core.mock import DummyCli from knack.completion import ARGCOMPLETE_ENV_NAME az_cli = DummyCli() telemetry.set_application(az_cli, ARGCOMPLETE_ENV_NAME) # mock user turns off telemetry with mock.patch('knack.config.CLIConfig.getboolean', return_value=False): self.assertFalse(telemetry.is_telemetry_enabled()) # mock user turns on telemetry with mock.patch('knack.config.CLIConfig.getboolean', return_value=True): self.assertTrue(telemetry.is_telemetry_enabled()) # mock to add current cloud name in CLOUDS_FORBIDDING_TELEMETRY with mock.patch('azure.cli.core.cloud.CLOUDS_FORBIDDING_TELEMETRY', [az_cli.cloud.name]): self.assertFalse(telemetry.is_telemetry_enabled())
def call_aladdin_service(command, parameters, version): _log_debug( 'call_aladdin_service: version: "%s", command: "%s", parameters: "%s"', version, command, parameters) response = None correlation_id = telemetry._session.correlation_id # pylint: disable=protected-access subscription_id = telemetry._get_azure_subscription_id() # pylint: disable=protected-access is_telemetry_enabled = telemetry.is_telemetry_enabled() telemetry_context = { 'correlationId': correlation_id, 'subscriptionId': subscription_id } telemetry_context = { k: v for k, v in telemetry_context.items() if v is not None and is_telemetry_enabled } if not is_telemetry_enabled: _log_debug(TELEMETRY_IS_DISABLED_STR) else: _log_debug(TELEMETRY_IS_ENABLED_STR) if subscription_id is None: _log_debug(TELEMETRY_MISSING_SUBSCRIPTION_ID_STR) if correlation_id is None: _log_debug(TELEMETRY_MISSING_CORRELATION_ID_STR) context = {**telemetry_context, "versionNumber": version} query = {"command": command, "parameters": parameters} api_url = 'https://app.aladdin.microsoft.com/api/v1.0/suggestions' headers = {'Content-Type': 'application/json'} try: response = requests.get(api_url, params={ 'query': json.dumps(query), 'clientType': 'AzureCli', 'context': json.dumps(context) }, headers=headers) except RequestException as ex: _log_debug('requests.get() exception: %s', ex) return response
def _set_aladdin_recommendations(self): """Set recommendations from aladdin service. Call the aladdin service API, parse the response and set the recommendations. """ import hashlib import json import requests from requests import RequestException from http import HTTPStatus from azure.cli.core import __version__ as version api_url = 'https://app.aladdin.microsoft.com/api/v1.0/suggestions' correlation_id = telemetry._session.correlation_id # pylint: disable=protected-access subscription_id = telemetry._get_azure_subscription_id() # pylint: disable=protected-access # Used for DDOS protection and rate limiting user_id = telemetry._get_user_azure_id() # pylint: disable=protected-access hashed_user_id = hashlib.sha256(user_id.encode('utf-8')).hexdigest() headers = { 'Content-Type': 'application/json', 'X-UserId': hashed_user_id } context = { 'versionNumber': version, 'errorType': self._get_error_type() } if telemetry.is_telemetry_enabled(): if correlation_id: context['correlationId'] = correlation_id if subscription_id: context['subscriptionId'] = subscription_id parameters = [ item for item in self.parameters if item not in ['--debug', '--verbose', '--only-show-errors'] ] query = {"command": self.command, "parameters": ','.join(parameters)} response = None try: response = requests.get(api_url, params={ 'query': json.dumps(query), 'clientType': 'AzureCli', 'context': json.dumps(context) }, headers=headers, timeout=1) except RequestException as ex: logger.debug('Recommendation requests.get() exception: %s', ex) telemetry.set_debug_info('AladdinRecommendationService', ex.__class__.__name__) recommendations = [] if response and response.status_code == HTTPStatus.OK: for result in response.json(): # parse the reponse and format the recommendation command, parameters, placeholders = result['command'],\ result['parameters'].split(','),\ result['placeholders'].split('♠') recommendation = 'az {} '.format(command) for parameter, placeholder in zip(parameters, placeholders): recommendation += '{} {} '.format(parameter, placeholder) recommendations.append(recommendation.strip()) self.aladdin_recommendations.extend(recommendations)
def _is_telemetry_enabled(): from azure.cli.core.telemetry import is_telemetry_enabled return is_telemetry_enabled()
def recommend_recovery_options(version, command, parameters, extension): from timeit import default_timer as timer start_time = timer() elapsed_time = None result = [] cmd_tbl = CommandTable.CMD_TBL _log_debug( 'recommend_recovery_options: version: "%s", command: "%s", parameters: "%s", extension: "%s"', version, command, parameters, extension) # if the user doesn't agree to telemetry... if not telemetry.is_telemetry_enabled(): _log_debug(TELEMETRY_MUST_BE_ENABLED_STR) return result # if the command is empty... if not command: # try to get the raw command field from telemetry. session = telemetry._session # pylint: disable=protected-access # get the raw command parsed by the CommandInvoker object. command = session.raw_command if command: _log_debug(f'Setting command to [{command}] from telemtry.') def append(line): result.append(line) def unable_to_help(command): msg = UNABLE_TO_HELP_FMT_STR.format(command=command) append(msg) def show_recommendation_header(command): msg = RECOMMENDATION_HEADER_FMT_STR.format(command=command) append(style_message(msg)) if extension: _log_debug('Detected extension. No action to perform.') if not command: _log_debug('Command is empty. No action to perform.') # if an extension is in-use or the command is empty... if extension or not command: return result # perform some rudimentary parsing to extract the parameters and command in a standard form command, parameters = normalize_and_sort_parameters( cmd_tbl, command, parameters) response = call_aladdin_service(command, parameters, version) # only show recommendations when we can contact the service. if response and response.status_code == HTTPStatus.OK: recommendations = get_recommendations_from_http_response(response) if recommendations: show_recommendation_header(command) for recommendation in recommendations: append(f"\t{recommendation}") # only prompt user to use "az find" for valid CLI commands # note: pylint has trouble resolving statically initialized variables, which is why # we need to disable the unsupported membership test rule elif any(cmd.startswith(command) for cmd in cmd_tbl.keys()): # pylint: disable=unsupported-membership-test unable_to_help(command) elapsed_time = timer() - start_time _log_debug( 'The overall time it took to process failure recovery recommendations was %.2fms.', elapsed_time * 1000) return result
def call_aladdin_service(command, parameters, version): logger.debug( 'call_aladdin_service: version: "%s", command: "%s", parameters: "%s"', version, command, parameters) response = None time_to_get_user_info = Timer() with time_to_get_user_info: correlation_id = get_correlation_id() subscription_id = get_subscription_id() set_property(TelemetryProperty.TimeToRetrieveUserInfoMs, time_to_get_user_info.elapsed_ms) is_telemetry_enabled = telemetry.is_telemetry_enabled() telemetry_context = { 'correlationId': correlation_id, 'subscriptionId': subscription_id } telemetry_context = { k: v for k, v in telemetry_context.items() if v is not None and is_telemetry_enabled } if not is_telemetry_enabled: logger.debug(TELEMETRY_IS_DISABLED_STR) else: logger.debug(TELEMETRY_IS_ENABLED_STR) if subscription_id is None: set_property(TelemetryProperty.NoSubscriptionId, True) logger.debug(TELEMETRY_MISSING_SUBSCRIPTION_ID_STR) if correlation_id is None: set_property(TelemetryProperty.NoCorrelationId, True) logger.debug(TELEMETRY_MISSING_CORRELATION_ID_STR) context = {**telemetry_context, "versionNumber": version} query = {"command": command, "parameters": parameters} api_url = 'https://app.aladdin.microsoft.com/api/v1.0/suggestions' headers = {'Content-Type': 'application/json'} try: round_trip_request_time = Timer() with round_trip_request_time: response = requests.get(api_url, params={ 'query': json.dumps(query), 'clientType': 'AzureCli', 'context': json.dumps(context), 'extensionVersion': VERSION }, headers=headers, timeout=(SERVICE_CONNECTION_TIMEOUT, None)) set_property(TelemetryProperty.RoundTripRequestTimeMs, round_trip_request_time.elapsed_ms) except RequestException as ex: if isinstance(ex, requests.Timeout): set_property(TelemetryProperty.RequestTimedOut, True) logger.debug('requests.get() exception: %s', ex) set_exception( exception=ex, fault_type=FaultType.RequestError.value, summary='HTTP Get Request to Aladdin suggestions endpoint failed.') return response
def is_telemetry_enabled(self): return core_telemetry.is_telemetry_enabled()