provider.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. """
  2. Specification for a provider interface
  3. """
  4. from __future__ import annotations
  5. from abc import ABCMeta
  6. from abc import abstractmethod
  7. from abc import abstractproperty
  8. from typing import Any
  9. from typing import TYPE_CHECKING
  10. if TYPE_CHECKING:
  11. from pyeventsystem.middleware import MiddlewareManager
  12. from cloudbridge.interfaces.resources import Configuration
  13. from cloudbridge.interfaces.resources import Instance
  14. from cloudbridge.interfaces.resources import PlacementZone
  15. from cloudbridge.interfaces.services import ComputeService
  16. from cloudbridge.interfaces.services import DnsService
  17. from cloudbridge.interfaces.services import NetworkingService
  18. from cloudbridge.interfaces.services import SecurityService
  19. from cloudbridge.interfaces.services import StorageService
  20. class CloudProvider(object):
  21. """
  22. Base interface for a cloud provider
  23. """
  24. __metaclass__ = ABCMeta
  25. @abstractmethod
  26. def __init__(self, config: dict[str, Any]) -> None:
  27. """
  28. Create a new provider instance given a dictionary of
  29. configuration attributes.
  30. :type config: :class:`dict`
  31. :param config: A dictionary object containing provider initialization
  32. values. Alternatively, this can be an iterable of
  33. key/value pairs (as tuples or other iterables of length
  34. two). See specific provider implementation for the
  35. required fields.
  36. :rtype: :class:`.CloudProvider`
  37. :return: a concrete provider instance
  38. """
  39. pass
  40. @abstractproperty
  41. def config(self) -> Configuration:
  42. """
  43. Returns the config object associated with this provider. This object
  44. is a subclass of :class:`dict` and will contain the properties
  45. provided at initialization time, grouped under `cloud_properties` and
  46. `credentials` keys. In addition, it also contains extra provider-wide
  47. properties such as the default result limit for `list()` queries.
  48. Example:
  49. .. code-block:: python
  50. config = { 'aws_access_key' : '<my_key>' }
  51. provider = factory.create_provider(ProviderList.AWS, config)
  52. print(provider.config['credentials'].get('aws_access_key'))
  53. print(provider.config.default_result_limit))
  54. # change provider result limit
  55. provider.config.default_result_limit = 100
  56. :rtype: :class:`.Configuration`
  57. :return: An object of class Configuration, which contains the values
  58. used to initialize the provider, as well as other global
  59. configuration properties.
  60. """
  61. pass
  62. @abstractproperty
  63. def middleware(self) -> MiddlewareManager:
  64. """
  65. Returns the middleware manager associated with this provider. The
  66. middleware manager can be used to add or remove middleware from
  67. cloudbridge. Refer to pyeventsystem documentation for more information
  68. on how the middleware manager works.
  69. :rtype: :class:`.MiddlewareManager`
  70. :return: An object of class MiddlewareManager, which can be used to
  71. add or remove middleware from cloudbridge.
  72. """
  73. pass
  74. @abstractmethod
  75. def clone(self, zone: PlacementZone | None = None) -> CloudProvider:
  76. """
  77. Create a clone of this provider. An optional `zone` parameter can be
  78. used to clone the provider to use a different zone.
  79. As each cloudbridge provider is restricted to a particular zone,
  80. this is useful when performing cross-zonal operations.
  81. Example:
  82. .. code-block:: python
  83. # list instances in all availability zones
  84. all_instances = []
  85. for zone in provider.compute.regions.current.zones:
  86. new_provider = provider.clone(zone=zone)
  87. all_instances.append(list(new_provider.compute.instances))
  88. print(all_instances)
  89. :param zone: Changes the provider's zone to the requested
  90. AvailabilityZone
  91. :type zone: :class:`.PlacementZone` object
  92. :rtype: :class:`.CloudProvider`
  93. :return: A clone of the CloudProvider, with zone changed to the
  94. requested zone.
  95. """
  96. pass
  97. @abstractmethod
  98. def authenticate(self) -> bool:
  99. """
  100. Checks whether a provider can be successfully authenticated with the
  101. configured settings. Clients are *not* required to call this method
  102. prior to accessing provider services, as most cloud connections are
  103. initialized lazily. The authenticate() method will return True if
  104. cloudbridge can establish a successful connection to the provider.
  105. It will raise an exception with the appropriate error details
  106. otherwise.
  107. Example:
  108. .. code-block:: python
  109. try:
  110. if provider.authenticate():
  111. print("Provider connection successful")
  112. except ProviderConnectionException as e:
  113. print("Could not authenticate with provider: %s" % (e, ))
  114. :rtype: :class:`bool`
  115. :return: ``True`` if authentication is successful.
  116. """
  117. pass
  118. @abstractmethod
  119. def has_service(self, service_type: str) -> bool:
  120. """
  121. Checks whether this provider supports a given service.
  122. Example:
  123. .. code-block:: python
  124. if provider.has_service(CloudServiceType.BUCKET):
  125. print("Provider supports object store services")
  126. provider.storage.buckets.list()
  127. :type service_type: :class:`.CloudServiceType`
  128. :param service_type: Type of service to check support for.
  129. :rtype: :class:`bool`
  130. :return: ``True`` if the service type is supported.
  131. """
  132. pass
  133. @abstractproperty
  134. def region_name(self) -> str | None:
  135. """
  136. Returns the region that this provider is connected to.
  137. All provider operations will take place within this region.
  138. :rtype: ``str``
  139. :return: a zone id
  140. """
  141. pass
  142. @abstractproperty
  143. def zone_name(self) -> str | None:
  144. """
  145. Returns the placement zone that this provider is connected to.
  146. All provider operations will take place within this zone. Placement
  147. zone must be within the provider default region.
  148. :rtype: ``str``
  149. :return: a zone id
  150. """
  151. pass
  152. # @abstractproperty
  153. # def account(self):
  154. # """
  155. # Provides access to all user account related services in this
  156. # provider. This includes listing available tenancies.
  157. #
  158. # :rtype: ``object`` of :class:`.ComputeService`
  159. # :return: a ComputeService object
  160. # """
  161. # pass
  162. @abstractproperty
  163. def compute(self) -> ComputeService:
  164. """
  165. Provides access to all compute related services in this provider.
  166. Example:
  167. .. code-block:: python
  168. regions = provider.compute.regions.list()
  169. vm_types = provider.compute.vm_types.list()
  170. instances = provider.compute.instances.list()
  171. images = provider.compute.images.list()
  172. # Alternatively
  173. for instance in provider.compute.instances:
  174. print(instance.name)
  175. :rtype: :class:`.ComputeService`
  176. :return: a ComputeService object
  177. """
  178. pass
  179. @abstractproperty
  180. def networking(self) -> NetworkingService:
  181. """
  182. Provide access to all network related services in this provider.
  183. Example:
  184. .. code-block:: python
  185. networks = provider.networking.networks.list()
  186. subnets = provider.networking.subnets.list()
  187. routers = provider.networking.routers.list()
  188. :rtype: :class:`.NetworkingService`
  189. :return: a NetworkingService object
  190. """
  191. @abstractproperty
  192. def security(self) -> SecurityService:
  193. """
  194. Provides access to key pair management and firewall control
  195. Example:
  196. .. code-block:: python
  197. keypairs = provider.security.keypairs.list()
  198. vm_firewalls = provider.security.vm_firewalls.list()
  199. :rtype: ``object`` of :class:`.SecurityService`
  200. :return: a SecurityService object
  201. """
  202. pass
  203. @abstractproperty
  204. def storage(self) -> StorageService:
  205. """
  206. Provides access to storage related services in this provider.
  207. This includes the volume, snapshot and bucket services,
  208. Example:
  209. .. code-block:: python
  210. volumes = provider.storage.volumes.list()
  211. snapshots = provider.storage.snapshots.list()
  212. if provider.has_service(CloudServiceType.BUCKET):
  213. print("Provider supports object store services")
  214. print(provider.storage.buckets.list())
  215. :rtype: :class:`.StorageService`
  216. :return: a StorageService object
  217. """
  218. pass
  219. @abstractproperty
  220. def dns(self) -> DnsService:
  221. """
  222. Provides access to all DNS related services.
  223. Example:
  224. .. code-block:: python
  225. if provider.has_service(CloudServiceType.DNS):
  226. print("Provider supports DNS services")
  227. dns_zones = provider.dns.host_zones.list()
  228. print(dns_zones)
  229. :rtype: :class:`.DnsService`
  230. :return: a DNS service object
  231. """
  232. pass
  233. class TestMockHelperMixin(object):
  234. """
  235. A helper class that providers mock drivers can use to be notified when a
  236. test setup/teardown occurs. This is useful when activating libraries
  237. like HTTPretty which take over socket communications.
  238. """
  239. def setUpMock(self) -> None:
  240. """
  241. Called before a test is started.
  242. """
  243. raise NotImplementedError(
  244. 'TestMockHelperMixin.setUpMock not implemented')
  245. def tearDownMock(self) -> None:
  246. """
  247. Called before test teardown.
  248. """
  249. raise NotImplementedError(
  250. 'TestMockHelperMixin.tearDownMock not implemented by this'
  251. ' provider')
  252. class ContainerProvider(object):
  253. """
  254. Represents a container instance, such as Docker or LXC
  255. """
  256. __metaclass__ = ABCMeta
  257. @abstractmethod
  258. def create_container(self) -> None:
  259. pass
  260. @abstractmethod
  261. def delete_container(self) -> None:
  262. pass
  263. class DeploymentProvider(object):
  264. """
  265. Represents a deployment provider, such as Ansible or Shell script provider
  266. """
  267. __metaclass__ = ABCMeta
  268. @abstractmethod
  269. def deploy(self, target: Instance) -> None:
  270. """
  271. Deploys on given target, where target is an Instance or Container
  272. """
  273. pass