provider.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. """Base implementation of a provider interface."""
  2. import functools
  3. import os
  4. from os.path import expanduser
  5. try:
  6. from configparser import SafeConfigParser
  7. except ImportError: # Python 2
  8. from ConfigParser import SafeConfigParser
  9. from cloudbridge.cloud.interfaces import CloudProvider
  10. from cloudbridge.cloud.interfaces.exceptions import ProviderConnectionException
  11. from cloudbridge.cloud.interfaces.resources import Configuration
  12. DEFAULT_RESULT_LIMIT = 50
  13. DEFAULT_WAIT_TIMEOUT = 600
  14. DEFAULT_WAIT_INTERVAL = 5
  15. # By default, use two locations for CloudBridge configuration
  16. CloudBridgeConfigPath = '/etc/cloudbridge.ini'
  17. CloudBridgeConfigLocations = [CloudBridgeConfigPath]
  18. UserConfigPath = os.path.join(expanduser('~'), '.cloudbridge')
  19. CloudBridgeConfigLocations.append(UserConfigPath)
  20. class BaseConfiguration(Configuration):
  21. def __init__(self, user_config):
  22. self.update(user_config)
  23. @property
  24. def default_result_limit(self):
  25. """
  26. Get the maximum number of results to return for a
  27. list method
  28. :rtype: ``int``
  29. :return: The maximum number of results to return
  30. """
  31. return self.get('default_result_limit', DEFAULT_RESULT_LIMIT)
  32. @property
  33. def default_wait_timeout(self):
  34. """
  35. Gets the default wait timeout for LifeCycleObjects.
  36. """
  37. return self.get('default_wait_timeout', DEFAULT_WAIT_TIMEOUT)
  38. @property
  39. def default_wait_interval(self):
  40. """
  41. Gets the default wait interval for LifeCycleObjects.
  42. """
  43. return self.get('default_wait_interval', DEFAULT_WAIT_INTERVAL)
  44. @property
  45. def debug_mode(self):
  46. """
  47. A flag indicating whether CloudBridge is in debug mode. Setting
  48. this to True will cause the underlying provider's debug
  49. output to be turned on.
  50. The flag can be toggled by sending in the cb_debug value via
  51. the config dictionary, or setting the CB_DEBUG environment variable.
  52. :rtype: ``bool``
  53. :return: Whether debug mode is on.
  54. """
  55. return self.get('cb_debug', os.environ.get('CB_DEBUG', False))
  56. class BaseCloudProvider(CloudProvider):
  57. def __init__(self, config):
  58. self._config = BaseConfiguration(config)
  59. self._config_parser = SafeConfigParser()
  60. self._config_parser.read(CloudBridgeConfigLocations)
  61. @property
  62. def config(self):
  63. return self._config
  64. @property
  65. def name(self):
  66. return str(self.__class__.__name__)
  67. def authenticate(self):
  68. """
  69. A basic implementation which simply runs a low impact command to
  70. check whether cloud credentials work. Providers should override with
  71. more efficient implementations.
  72. """
  73. try:
  74. self.security.key_pairs.list()
  75. return True
  76. except Exception as e:
  77. raise ProviderConnectionException(
  78. "Authentication with cloud provider failed: %s" % (e,))
  79. def _deepgetattr(self, obj, attr):
  80. """Recurses through an attribute chain to get the ultimate value."""
  81. return functools.reduce(getattr, attr.split('.'), obj)
  82. def has_service(self, service_type):
  83. """
  84. Checks whether this provider supports a given service.
  85. :type service_type: str or :class:``.CloudServiceType``
  86. :param service_type: Type of service to check support for.
  87. :rtype: bool
  88. :return: ``True`` if the service type is supported.
  89. """
  90. try:
  91. if self._deepgetattr(self, service_type):
  92. return True
  93. except AttributeError:
  94. pass # Undefined service type
  95. except NotImplementedError:
  96. pass # service not implemented
  97. return False
  98. def _get_config_value(self, key, default_value):
  99. """
  100. A convenience method to extract a configuration value.
  101. :type key: str
  102. :param key: a field to look for in the ``self.config`` field
  103. :type default_value: anything
  104. :param default_value: the default value to return if a value for the
  105. ``key`` is not available
  106. :return: a configuration value for the supplied ``key``
  107. """
  108. if isinstance(self.config, dict) and self.config.get(key):
  109. return self.config.get(key, default_value)
  110. elif hasattr(self.config, key) and getattr(self.config, key):
  111. return getattr(self.config, key)
  112. elif (self._config_parser.has_option(self.PROVIDER_ID, key) and
  113. self._config_parser.get(self.PROVIDER_ID, key)):
  114. return self._config_parser.get(self.PROVIDER_ID, key)
  115. return default_value