github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/acceptancetests/jujupy/exceptions.py (about) 1 # This file is part of JujuPy, a library for driving the Juju CLI. 2 # Copyright 2013-2017 Canonical Ltd. 3 # 4 # This program is free software: you can redistribute it and/or modify it 5 # under the terms of the Lesser GNU General Public License version 3, as 6 # published by the Free Software Foundation. 7 # 8 # This program is distributed in the hope that it will be useful, but WITHOUT 9 # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, 10 # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser 11 # GNU General Public License for more details. 12 # 13 # You should have received a copy of the Lesser GNU General Public License 14 # along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 import re 17 import subprocess 18 from datetime import timedelta 19 20 __metaclass__ = type 21 22 23 class StatusTimeout(Exception): 24 """Raised when 'juju status' timed out.""" 25 26 class ControllersTimeout(Exception): 27 """Raised when 'juju show-controller' timed out.""" 28 29 class SoftDeadlineExceeded(Exception): 30 """Raised when an overall client operation takes too long.""" 31 32 def __init__(self): 33 super(SoftDeadlineExceeded, self).__init__( 34 'Operation exceeded deadline.') 35 36 37 class NoProvider(Exception): 38 """Raised when an environment defines no provider.""" 39 40 41 class TypeNotAccepted(Exception): 42 """Raised when the provided type was not accepted.""" 43 44 45 class NameNotAccepted(Exception): 46 """Raised when the provided name was not accepted.""" 47 48 49 class InvalidEndpoint(Exception): 50 """Raised when the provided endpoint was deemed invalid.""" 51 52 53 class AuthNotAccepted(Exception): 54 """Raised when the provided auth was not accepted.""" 55 56 57 class NoActiveModel(Exception): 58 """Raised when no active model could be found.""" 59 60 61 class NoActiveControllers(Exception): 62 """Raised when no active environment could be found.""" 63 64 65 class ErroredUnit(Exception): 66 67 def __init__(self, unit_name, state): 68 msg = '%s is in state %s' % (unit_name, state) 69 Exception.__init__(self, msg) 70 self.unit_name = unit_name 71 self.state = state 72 73 74 class UpgradeMongoNotSupported(Exception): 75 76 def __init__(self): 77 super(UpgradeMongoNotSupported, self).__init__( 78 'This client does not support upgrade-mongo') 79 80 81 class CannotConnectEnv(subprocess.CalledProcessError): 82 83 def __init__(self, e): 84 super(CannotConnectEnv, self).__init__(e.returncode, e.cmd, e.output) 85 86 87 class StatusNotMet(Exception): 88 89 _fmt = 'Expected status not reached in {env}.' 90 91 def __init__(self, environment_name, status): 92 self.env = environment_name 93 self.status = status 94 95 def __str__(self): 96 return self._fmt.format(env=self.env) 97 98 99 class AgentsNotStarted(StatusNotMet): 100 101 _fmt = 'Timed out waiting for agents to start in {env}.' 102 103 104 class VersionsNotUpdated(StatusNotMet): 105 106 _fmt = 'Some versions did not update.' 107 108 109 class WorkloadsNotReady(StatusNotMet): 110 111 _fmt = 'Workloads not ready in {env}.' 112 113 114 class ApplicationsNotStarted(StatusNotMet): 115 116 _fmt = 'Timed out waiting for applications to start in {env}.' 117 118 119 class VotingNotEnabled(StatusNotMet): 120 121 _fmt = 'Timed out waiting for voting to be enabled in {env}.' 122 123 class LXDProfileNotAvailable(Exception): 124 125 _fmt = 'Timed out waiting for LXDProfile {profile_name} on machine-{machine}.' 126 127 def __init__(self, machine, profile_name): 128 self.profile_name = profile_name 129 self.machine = machine 130 131 def __str__(self): 132 return self._fmt.format(profile_name=self.profile_name, machine=self.machine) 133 134 class LXDProfilesNotAvailable(Exception): 135 136 _fmt = 'Timed out waiting for LXDProfiles {profile_names}' 137 138 def __init__(self, profile_names): 139 self.profile_names = profile_names 140 141 def __str__(self): 142 return self._fmt.format(profile_names=self.profile_names) 143 144 class StatusError(Exception): 145 """Generic error for Status.""" 146 147 recoverable = True 148 149 # This has to be filled in after the classes are declared. 150 ordering = [] 151 152 @classmethod 153 def priority(cls): 154 """Get the priority of the StatusError as an number. 155 156 Lower number means higher priority. This can be used as a key 157 function in sorting.""" 158 return cls.ordering.index(cls) 159 160 161 class MachineError(StatusError): 162 """Error in machine-status.""" 163 164 recoverable = False 165 166 167 class ProvisioningError(MachineError): 168 """Machine experianced a 'provisioning error'.""" 169 170 171 class StuckAllocatingError(MachineError): 172 """Machine did not transition out of 'allocating' state.""" 173 174 recoverable = True 175 176 177 class UnitError(StatusError): 178 """Error in a unit's status.""" 179 180 181 class HookFailedError(UnitError): 182 """A unit hook has failed.""" 183 184 def __init__(self, item_name, msg): 185 match = re.search('^hook failed: "([^"]+)"$', msg) 186 if match: 187 msg = match.group(1) 188 super(HookFailedError, self).__init__(item_name, msg) 189 190 191 class InstallError(HookFailedError): 192 """The unit's install hook has failed.""" 193 194 recoverable = True 195 196 197 class AppError(StatusError): 198 """Error in an application's status.""" 199 200 201 class AgentError(StatusError): 202 """Error in a juju agent.""" 203 204 205 class AgentUnresolvedError(AgentError): 206 """Agent error has not recovered in a reasonable time.""" 207 208 # This is the time limit set by IS for recovery from an agent error. 209 a_reasonable_time = timedelta(minutes=5) 210 211 212 StatusError.ordering = [ 213 ProvisioningError, StuckAllocatingError, MachineError, InstallError, 214 AgentUnresolvedError, HookFailedError, UnitError, AppError, AgentError, 215 StatusError, 216 ]