1# -------------------------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for license information. 4# -------------------------------------------------------------------------------------------- 5 6import sys 7 8import azure.cli.core.telemetry as telemetry 9from knack.util import CLIError 10from knack.log import get_logger 11 12logger = get_logger(__name__) 13# pylint: disable=unnecessary-pass 14 15 16# Error types in AzureCLI are from different sources, and there are many general error types like CLIError, AzureError. 17# Besides, many error types with different names are actually showing the same kind of error. 18# For example, CloudError, CLIError and ValidationError all could be a resource-not-found error. 19# Therefore, here we define the new error classes to map and categorize all of the error types from different sources. 20 21 22# region: Base Layer 23# Base class for all the AzureCLI defined error classes. 24class AzCLIError(CLIError): 25 """ Base class for all the AzureCLI defined error classes. 26 DO NOT raise this error class in your codes. """ 27 28 def __init__(self, error_msg, recommendation=None): 29 # error message 30 self.error_msg = error_msg 31 32 # manual recommendations provided based on developers' knowledge 33 self.recommendations = [] 34 self.set_recommendation(recommendation) 35 36 # AI recommendations provided by Aladdin service, with tuple form: (recommendation, description) 37 self.aladdin_recommendations = [] 38 39 # exception trace for the error 40 self.exception_trace = None 41 super().__init__(error_msg) 42 43 def set_recommendation(self, recommendation): 44 """" Set manual recommendations for the error. 45 Command module or extension authors could call this method to provide recommendations, 46 the recommendations will be printed after the error message, one recommendation per line 47 """ 48 if isinstance(recommendation, str): 49 self.recommendations.append(recommendation) 50 elif isinstance(recommendation, list): 51 self.recommendations.extend(recommendation) 52 53 def set_aladdin_recommendation(self, recommendations): 54 """ Set aladdin recommendations for the error. 55 One item should be a tuple with the form: (recommendation, description) 56 """ 57 self.aladdin_recommendations.extend(recommendations) 58 59 def set_exception_trace(self, exception_trace): 60 self.exception_trace = exception_trace 61 62 def print_error(self): 63 from azure.cli.core.azlogging import CommandLoggerContext 64 from azure.cli.core.style import print_styled_text 65 with CommandLoggerContext(logger): 66 # print error message 67 logger.error(self.error_msg) 68 69 # print exception trace if there is 70 if self.exception_trace: 71 logger.exception(self.exception_trace) 72 73 # print recommendations to action 74 if self.recommendations: 75 for recommendation in self.recommendations: 76 print(recommendation, file=sys.stderr) 77 78 if self.aladdin_recommendations: 79 print('\nTRY THIS:', file=sys.stderr) 80 for recommendation, description in self.aladdin_recommendations: 81 print_styled_text(recommendation, file=sys.stderr) 82 print_styled_text(description, file=sys.stderr) 83 84 def send_telemetry(self): 85 telemetry.set_error_type(self.__class__.__name__) 86# endregion 87 88 89# region: Second Layer 90# Main categories of the AzureCLI error types, used for Telemetry analysis 91class UserFault(AzCLIError): 92 """ Users should be responsible for the errors. 93 DO NOT raise this error class in your codes. """ 94 def send_telemetry(self): 95 super().send_telemetry() 96 telemetry.set_user_fault(self.error_msg) 97 98 99class ServiceError(AzCLIError): 100 """ Azure Services should be responsible for the errors. 101 DO NOT raise this error class in your codes. """ 102 def send_telemetry(self): 103 super().send_telemetry() 104 telemetry.set_failure(self.error_msg) 105 106 107class ClientError(AzCLIError): 108 """ AzureCLI should be responsible for the errors. 109 DO NOT raise this error class in your codes. """ 110 def send_telemetry(self): 111 super().send_telemetry() 112 telemetry.set_failure(self.error_msg) 113 if self.exception_trace: 114 telemetry.set_exception(self.exception_trace, '') 115 116 117class UnknownError(AzCLIError): 118 """ Unclear errors, could not know who should be responsible for the errors. 119 DO NOT raise this error class in your codes. """ 120 def send_telemetry(self): 121 super().send_telemetry() 122 telemetry.set_failure(self.error_msg) 123 124# endregion 125 126 127# region: Third Layer 128# Specific categories of the AzureCLI error types 129# Raise the error classes here in your codes. Avoid using fallback error classes unless you can not find a proper one. 130# Command related error types 131class CommandNotFoundError(UserFault): 132 """ Command is misspelled or not recognized by AzureCLI. """ 133 pass 134 135 136# Argument related error types 137class UnrecognizedArgumentError(UserFault): 138 """ Argument is misspelled or not recognized by AzureCLI. """ 139 pass 140 141 142class RequiredArgumentMissingError(UserFault): 143 """ Required argument is not specified. """ 144 pass 145 146 147class MutuallyExclusiveArgumentError(UserFault): 148 """ Arguments can not be specified together. """ 149 pass 150 151 152class InvalidArgumentValueError(UserFault): 153 """ Argument value is not valid. """ 154 pass 155 156 157class ArgumentUsageError(UserFault): 158 """ Fallback of the argument usage related errors. 159 Avoid using this class unless the error can not be classified 160 into the Argument related specific error types. """ 161 pass 162 163 164# Response related error types 165class BadRequestError(UserFault): 166 """ Bad request from client: 400 error """ 167 pass 168 169 170class UnauthorizedError(UserFault): 171 """ Unauthorized request: 401 error """ 172 pass 173 174 175class ForbiddenError(UserFault): 176 """ Service refuse to response: 403 error """ 177 pass 178 179 180class ResourceNotFoundError(UserFault): 181 """ Can not find Azure resources: 404 error """ 182 pass 183 184 185class AzureInternalError(ServiceError): 186 """ Azure service internal error: 5xx error """ 187 pass 188 189 190class AzureResponseError(UserFault): 191 """ Fallback of the response related errors. 192 Avoid using this class unless the error can not be classified 193 into the Response related specific error types. """ 194 pass 195 196 197# Request related error types 198class AzureConnectionError(UserFault): 199 """ Connection issues like connection timeout, aborted or broken. """ 200 pass 201 202 203class ClientRequestError(UserFault): 204 """ Fallback of the request related errors. Error occurs while attempting 205 to make a request to the service. No request is sent. 206 Avoid using this class unless the error can not be classified 207 into the Request related specific errors types. """ 208 pass 209 210 211# File operation related error types 212class FileOperationError(UserFault): 213 """ For file or directory operation related errors. """ 214 pass 215 216 217# Keyboard interrupt error type 218class ManualInterrupt(UserFault): 219 """ Keyboard interrupt. """ 220 pass 221 222 223class NoTTYError(UserFault): 224 """ No tty available for prompt. """ 225 pass 226 227 228# ARM template related error types 229class InvalidTemplateError(UserFault): 230 """ ARM template validation fails. It could be caused by incorrect template files or parameters """ 231 pass 232 233 234class DeploymentError(UserFault): 235 """ ARM template deployment fails. Template file is valid, and error occurs in deployment. """ 236 pass 237 238 239# Validation related error types 240class ValidationError(UserFault): 241 """ Fallback of the errors in validation functions. 242 Avoid using this class unless the error can not be classified into 243 the Argument, Request and Response related specific error types. """ 244 pass 245 246 247class UnclassifiedUserFault(UserFault): 248 """ Fallback of the UserFault related error types. 249 Avoid using this class unless the error can not be classified into 250 the UserFault related specific error types. 251 """ 252 pass 253 254 255# CLI internal error type 256class CLIInternalError(ClientError): 257 """ AzureCLI internal error """ 258 pass 259 260 261# Client error for az next 262class RecommendationError(ClientError): 263 """ The client error raised by `az next`. It is needed in `az next` to skip error records. """ 264 pass 265 266 267class AuthenticationError(ServiceError): 268 """ Raised when AAD authentication fails. """ 269 270# endregion 271