blob: 7b0ad4f202304a711241320def6f8d404b09201f [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Optional
from typing import Callable
from typing import Union
from typing import cast
from enum import Enum
from libcloud.utils.py3 import httplib
from libcloud.utils.py3 import _real_unicode
if False:
# Work around for MYPY for cyclic import problem
from libcloud.compute.base import BaseDriver
__all__ = [
"Type",
"LibcloudError",
"MalformedResponseError",
"ProviderError",
"InvalidCredsError",
"InvalidCredsException",
"LazyList"
]
class Type(str, Enum):
@classmethod
def tostring(cls, value):
# type: (Union[Enum, str]) -> str
"""Return the string representation of the state object attribute
:param str value: the state object to turn into string
:return: the uppercase string that represents the state object
:rtype: str
"""
value = cast(Enum, value)
return str(value._value_).upper()
@classmethod
def fromstring(cls, value):
# type: (str) -> str
"""Return the state object attribute that matches the string
:param str value: the string to look up
:return: the state object attribute that matches the string
:rtype: str
"""
return getattr(cls, value.upper(), None)
"""
NOTE: These methods are here for backward compatibility reasons where
Type values were simple strings and Type didn't inherit from Enum.
"""
def __eq__(self, other):
if isinstance(other, Type):
return other.value == self.value
elif isinstance(other, (str, _real_unicode)):
return self.value == other
return super(Type, self).__eq__(other)
def upper(self):
return self.value.upper() # pylint: disable=no-member
def lower(self):
return self.value.lower() # pylint: disable=no-member
def __ne__(self, other):
return not self.__eq__(other)
def __str__(self):
return str(self.value)
def __repr__(self):
return self.value
def __hash__(self):
return id(self)
class LibcloudError(Exception):
"""The base class for other libcloud exceptions"""
def __init__(self, value, driver=None):
# type: (str, BaseDriver) -> None
super(LibcloudError, self).__init__(value)
self.value = value
self.driver = driver
def __str__(self):
return self.__repr__()
def __repr__(self):
return ("<LibcloudError in " +
repr(self.driver) +
" " +
repr(self.value) + ">")
class MalformedResponseError(LibcloudError):
"""Exception for the cases when a provider returns a malformed
response, e.g. you request JSON and provider returns
'<h3>something</h3>' due to some error on their side."""
def __init__(self, value, body=None, driver=None):
# type: (str, Optional[str], Optional[BaseDriver]) -> None
self.value = value
self.driver = driver
self.body = body
def __str__(self):
return self.__repr__()
def __repr__(self):
return ("<MalformedResponseException in " +
repr(self.driver) +
" " +
repr(self.value) +
">: " +
repr(self.body))
class ProviderError(LibcloudError):
"""
Exception used when provider gives back
error response (HTTP 4xx, 5xx) for a request.
Specific sub types can be derived for errors like
HTTP 401 : InvalidCredsError
HTTP 404 : NodeNotFoundError, ContainerDoesNotExistError
"""
def __init__(self, value, http_code, driver=None):
# type: (str, int, Optional[BaseDriver]) -> None
super(ProviderError, self).__init__(value=value, driver=driver)
self.http_code = http_code
def __str__(self):
return self.__repr__()
def __repr__(self):
return repr(self.value)
class InvalidCredsError(ProviderError):
"""Exception used when invalid credentials are used on a provider."""
def __init__(self, value='Invalid credentials with the provider',
driver=None):
# type: (str, Optional[BaseDriver]) -> None
super(InvalidCredsError, self).__init__(value,
http_code=httplib.UNAUTHORIZED,
driver=driver)
# Deprecated alias of :class:`InvalidCredsError`
InvalidCredsException = InvalidCredsError
class ServiceUnavailableError(ProviderError):
"""Exception used when a provider returns 503 Service Unavailable."""
def __init__(self, value='Service unavailable at provider', driver=None):
# type: (str, Optional[BaseDriver]) -> None
super(ServiceUnavailableError, self).__init__(
value,
http_code=httplib.SERVICE_UNAVAILABLE,
driver=driver
)
class LazyList(object):
def __init__(self, get_more, value_dict=None):
# type: (Callable, Optional[dict]) -> None
self._data = [] # type: list
self._last_key = None
self._exhausted = False
self._all_loaded = False
self._get_more = get_more
self._value_dict = value_dict or {}
def __iter__(self):
if not self._all_loaded:
self._load_all()
data = self._data
for i in data:
yield i
def __getitem__(self, index):
if index >= len(self._data) and not self._all_loaded:
self._load_all()
return self._data[index]
def __len__(self):
self._load_all()
return len(self._data)
def __repr__(self):
self._load_all()
repr_string = ', ' .join([repr(item) for item in self._data])
repr_string = '[%s]' % (repr_string)
return repr_string
def _load_all(self):
while not self._exhausted:
newdata, self._last_key, self._exhausted = \
self._get_more(last_key=self._last_key,
value_dict=self._value_dict)
self._data.extend(newdata)
self._all_loaded = True