3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """Exceptions related to Managed VM deployments."""
22 class Error(Exception):
23 """Base error class for google.appengine.client.services."""
27 class PermanentAppError(Error
):
28 """Base class for app config related errors we are unable to recover from.
30 Handlers should catch this type of errors since retrying is of no use.
33 def __init__(self
, end_user_message
, internal_message
=None):
37 end_user_message: The message to forward to appcfg so it can be
38 displayed to the end user.
39 internal_message: (optional) Error message to log as error.
41 # Use the base Exception class message field to store the end_user_message.
42 super(PermanentAppError
, self
).__init
__(end_user_message
)
43 self
.internal_message
= internal_message
46 logging
.debug('End user message: %s', self
.message
)
47 if self
.internal_message
:
48 logging
.error(self
.internal_message
)
51 # TODO: Some of these exceptions specify meaningful error messages, while
52 # others rely on the caller to do so. We should be consistent about this.
54 # TODO: Some exceptions here are specific to particular modules,
55 # while some are generic and applicable across modules. On one hand, if
56 # module-specific Exceptions were defined in their respective modules, there is
57 # no risk of misapplying them in improper places. On the other hand, keeping
58 # all errors in one file is convenient, and allows us to avoid having to disable
59 # catching-non-exception lint errors (caused because pylint doesn't trace the
60 # inheritance across files).
63 class TransientError(Error
):
64 """Base class for transient errors that should lead to a retry of the task."""
67 class GlobalConfigLoadError(TransientError
):
68 """Thrown if there was an error when loading the GlobalConfig for the app."""
71 class RobotSetupError(PermanentAppError
):
72 """Thrown if there was an error with the robot setup."""
75 class InvalidBucketConfigurationError(PermanentAppError
):
76 """Thrown if there is no GCS bucket configured in AdminConfig."""
79 # TODO: Improve this with doc links / next steps the user can take.
80 PermanentAppError
.__init
__(
82 'Severe: This app has no associated Google Cloud Storage bucket.',
83 'Configuration error: Neither admin_config.vm_config_bigstore_bucket'
84 'nor admin_config.default_bigstore_bucket is set. Deployment aborted.')
87 class InvalidUserInstallItem(PermanentAppError
):
88 """Thrown if one of the apt_get_install items is invalid."""
90 def __init__(self
, bad_package
):
91 msg
= 'Invalid apt-get-install package in vm_settings:"%s"' % bad_package
92 PermanentAppError
.__init
__(self
, msg
)
95 class InvalidScopeConfigurationError(PermanentAppError
):
96 """Thrown if there are incompatible storage scopes in vm_settings."""
99 PermanentAppError
.__init
__(
101 'Severe: Invalid storage scope configuration. '
102 'Only one of devstorage.read_only, devstorage.read_write, '
103 'devstorage.full_control can be used at a time.')
106 class InvalidRootSetupCommandError(PermanentAppError
):
107 """Thrown if the root_setup_command format is invalid."""
110 PermanentAppError
.__init
__(
112 'Severe: Invalid root_setup_command format string.'
113 'Invalid root_setup_command format string.')
116 class StaleGlobalConfigError(TransientError
):
117 """Thrown if the GlobalConfig is older than the requester's."""
119 def __init__(self
, msg
):
120 TransientError
.__init
__(self
, msg
)
123 class AppLockError(PermanentAppError
):
124 """Thrown if there was an error with the AppLock."""
127 PermanentAppError
.__init
__(
129 'An internal error occurred. Please retry.',
130 'Unable to load the AppLock using the provided applock_key.')
133 class UnknownAppIdError(PermanentAppError
):
134 """Thrown if the provided app id does not exist."""
137 class UnknownVersionIdError(PermanentAppError
):
138 """Thrown if the provided version id does not exist."""
141 class AdminConfigLoadError(TransientError
):
142 """Thrown if there was an error when loading the AdminConfig of the app."""
145 class AppInfoLoadError(TransientError
):
146 """Thrown if there was an error when loading the AppInfo for the app."""
149 class GcsWriteError(TransientError
):
150 """Thrown if there was an error when writing to cloud storage."""
153 class InvalidLockdownzResponseError(TransientError
):
154 """Thrown if a lockdownz request to the agent returns an invalid response."""
157 class InvalidEnvVariableError(PermanentAppError
):
158 """Thrown if an environment variable name or value cannot be supported."""
161 class MachineTypeInfoNotFoundError(PermanentAppError
):
162 """Thrown when the MachineTypeInfo is not found."""
165 class MachineTypeInfoLoadError(TransientError
):
166 """Thrown when the MachineTypeInfo can't be loaded."""
169 class InvalidImageError(PermanentAppError
):
170 """Thrown if the user requested image can not be found."""
173 class InvalidVmSettingsError(PermanentAppError
):
174 """Thrown if the VM settings dictionary contains an invalid key or Value."""
177 class InvalidDiskSizeConfiguration(InvalidVmSettingsError
):
178 """Thrown if the user requsted an invalid disk size."""
181 class GoManifestError(PermanentAppError
):
182 """Thrown if there is a problem with the Go manifest."""
185 class ReplicaPoolTimeoutError(TransientError
):
186 """Thrown if there was a timeout with a ReplicaPool operation."""
189 class MigrateDuplicateZoneError(PermanentAppError
):
190 """Thrown if attempted to migrating a replica pool to its existing zone."""
193 class ReplicaPoolTransientError(TransientError
):
194 """Thrown if there was an 5xx HttpError from the ReplicaPool service."""
197 class InvalidInstanceError(PermanentAppError
):
198 """Thrown by (un)lock method, if deployment or instance could not be found."""
201 class LockOperationError(PermanentAppError
):
202 """Thrown by (un)lock method, in case of a downstream failure."""
205 class OperationAborted(PermanentAppError
):
206 """Thrown if operation was aborted (AppLock was revoked). Used internally."""
209 # Errors thrown by api utility classes
210 class OperationDidNotCompleteError(TransientError
):
211 """Thrown if an operation did not go to DONE status in time."""
215 class OperationFailedError(PermanentAppError
):
216 """Thrown if an operation threw an error."""
218 def __init__(self
, message
, errors
):
219 super(OperationFailedError
, self
).__init
__(
220 message
, internal_message
='Operation errors: %s' % str(errors
))
224 class ResourceAlreadyExistsError(PermanentAppError
):
225 """Thrown if the resource being inserted already exists."""
229 class ResourceDoesNotExistError(PermanentAppError
):
230 """Thrown if the resource being updated/deleted doesn't exist."""