github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 19 from datetime import timedelta 20 21 22 __metaclass__ = type 23 24 25 class StatusTimeout(Exception): 26 """Raised when 'juju status' timed out.""" 27 28 class ControllersTimeout(Exception): 29 """Raised when 'juju show-controller' timed out.""" 30 31 class SoftDeadlineExceeded(Exception): 32 """Raised when an overall client operation takes too long.""" 33 34 def __init__(self): 35 super(SoftDeadlineExceeded, self).__init__( 36 'Operation exceeded deadline.') 37 38 39 class NoProvider(Exception): 40 """Raised when an environment defines no provider.""" 41 42 43 class TypeNotAccepted(Exception): 44 """Raised when the provided type was not accepted.""" 45 46 47 class NameNotAccepted(Exception): 48 """Raised when the provided name was not accepted.""" 49 50 51 class InvalidEndpoint(Exception): 52 """Raised when the provided endpoint was deemed invalid.""" 53 54 55 class AuthNotAccepted(Exception): 56 """Raised when the provided auth was not accepted.""" 57 58 59 class NoActiveModel(Exception): 60 """Raised when no active model could be found.""" 61 62 63 class NoActiveControllers(Exception): 64 """Raised when no active environment could be found.""" 65 66 67 class ErroredUnit(Exception): 68 69 def __init__(self, unit_name, state): 70 msg = '%s is in state %s' % (unit_name, state) 71 Exception.__init__(self, msg) 72 self.unit_name = unit_name 73 self.state = state 74 75 76 class UpgradeMongoNotSupported(Exception): 77 78 def __init__(self): 79 super(UpgradeMongoNotSupported, self).__init__( 80 'This client does not support upgrade-mongo') 81 82 83 class CannotConnectEnv(subprocess.CalledProcessError): 84 85 def __init__(self, e): 86 super(CannotConnectEnv, self).__init__(e.returncode, e.cmd, e.output) 87 88 89 class StatusNotMet(Exception): 90 91 _fmt = 'Expected status not reached in {env}.' 92 93 def __init__(self, environment_name, status): 94 self.env = environment_name 95 self.status = status 96 97 def __str__(self): 98 return self._fmt.format(env=self.env) 99 100 101 class AgentsNotStarted(StatusNotMet): 102 103 _fmt = 'Timed out waiting for agents to start in {env}.' 104 105 106 class VersionsNotUpdated(StatusNotMet): 107 108 _fmt = 'Some versions did not update.' 109 110 111 class WorkloadsNotReady(StatusNotMet): 112 113 _fmt = 'Workloads not ready in {env}.' 114 115 116 class ApplicationsNotStarted(StatusNotMet): 117 118 _fmt = 'Timed out waiting for applications to start in {env}.' 119 120 121 class VotingNotEnabled(StatusNotMet): 122 123 _fmt = 'Timed out waiting for voting to be enabled in {env}.' 124 125 class LXDProfileNotAvailable(Exception): 126 127 _fmt = 'Timed out waiting for LXDProfile {profile_name} on machine-{machine}.' 128 129 def __init__(self, machine, profile_name): 130 self.profile_name = profile_name 131 self.machine = machine 132 133 def __str__(self): 134 return self._fmt.format(env=self.profile_name) 135 136 class StatusError(Exception): 137 """Generic error for Status.""" 138 139 recoverable = True 140 141 # This has to be filled in after the classes are declared. 142 ordering = [] 143 144 @classmethod 145 def priority(cls): 146 """Get the priority of the StatusError as an number. 147 148 Lower number means higher priority. This can be used as a key 149 function in sorting.""" 150 return cls.ordering.index(cls) 151 152 153 class MachineError(StatusError): 154 """Error in machine-status.""" 155 156 recoverable = False 157 158 159 class ProvisioningError(MachineError): 160 """Machine experianced a 'provisioning error'.""" 161 162 163 class StuckAllocatingError(MachineError): 164 """Machine did not transition out of 'allocating' state.""" 165 166 recoverable = True 167 168 169 class UnitError(StatusError): 170 """Error in a unit's status.""" 171 172 173 class HookFailedError(UnitError): 174 """A unit hook has failed.""" 175 176 def __init__(self, item_name, msg): 177 match = re.search('^hook failed: "([^"]+)"$', msg) 178 if match: 179 msg = match.group(1) 180 super(HookFailedError, self).__init__(item_name, msg) 181 182 183 class InstallError(HookFailedError): 184 """The unit's install hook has failed.""" 185 186 recoverable = True 187 188 189 class AppError(StatusError): 190 """Error in an application's status.""" 191 192 193 class AgentError(StatusError): 194 """Error in a juju agent.""" 195 196 197 class AgentUnresolvedError(AgentError): 198 """Agent error has not recovered in a reasonable time.""" 199 200 # This is the time limit set by IS for recovery from an agent error. 201 a_reasonable_time = timedelta(minutes=5) 202 203 204 StatusError.ordering = [ 205 ProvisioningError, StuckAllocatingError, MachineError, InstallError, 206 AgentUnresolvedError, HookFailedError, UnitError, AppError, AgentError, 207 StatusError, 208 ]