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      ]