provider_development.rst 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. Provider Development Walkthrough
  2. ================================
  3. This guide will walk you through the basic process of developing a new provider
  4. for CloudBridge.
  5. 1. We start off by creating a new folder for the provider within the
  6. cloudbridge/cloud/providers folder. In this case: gce
  7. 2. Add a provider.py file. This file will contain the main implementation of
  8. the cloud provider and will be the entry point that cloudbridge uses for all
  9. provider related services. You will need to subclass BaseCloudProvider and add
  10. a class variable named PROVIDER_ID.
  11. .. code-block:: python
  12. from cloudbridge.cloud.base import BaseCloudProvider
  13. class GCECloudProvider(BaseCloudProvider):
  14. PROVIDER_ID = 'gce'
  15. def __init__(self, config):
  16. super(GCECloudProvider, self).__init__(config)
  17. 3. Add an __init__.py to the cloudbridge/cloud/providers/gce folder and export
  18. the provider.
  19. .. code-block:: python
  20. from .provider import GCECloudProvider # noqa
  21. .. tip ::
  22. You can view the code so far here: `commit 1`_
  23. 4. Next, we need to register the provider with the factory.
  24. This only requires that you register the provider's id in the ProviderList
  25. Add GCE to the ProviderList.
  26. 5. Run the test suite. We will get the tests passing on py27 first.
  27. .. code-block:: bash
  28. export CB_TEST_PROVIDER=gce
  29. tox -e py27
  30. You should see the tests fail with the following message:
  31. .. code-block:: bash
  32. TypeError: Can't instantiate abstract class GCECloudProvider with abstract
  33. methods block_store, compute, object_store, security, network
  34. 6. Therefore, our next step is to implement these methods. We can start off by
  35. implementing these methods in provider.py and raising a NotImplementedError.
  36. .. code-block:: python
  37. @property
  38. def compute(self):
  39. raise NotImplementedError(
  40. "GCECloudProvider does not implement this service")
  41. @property
  42. def network(self):
  43. raise NotImplementedError(
  44. "GCECloudProvider does not implement this service")
  45. @property
  46. def security(self):
  47. return self._security
  48. @property
  49. def block_store(self):
  50. raise NotImplementedError(
  51. "GCECloudProvider does not implement this service")
  52. @property
  53. def object_store(self):
  54. raise NotImplementedError(
  55. "GCECloudProvider does not implement this service")
  56. Running the tests now will complain as much. We will next implement each
  57. Service in turn, starting with the Compute service.
  58. 7. We will start with the compute service. Add a services.py file.
  59. .. code-block:: python
  60. from cloudbridge.cloud.base.services import BaseSecurityService
  61. class GCESecurityService(BaseSecurityService):
  62. def __init__(self, provider):
  63. super(GCESecurityService, self).__init__(provider)
  64. 8. We can now return this new service from the security property in provider.py
  65. as follows:
  66. .. code-block:: python
  67. def __init__(self, config):
  68. super(GCECloudProvider, self).__init__(config)
  69. self._security = GCESecurityService(self)
  70. @property
  71. def security(self):
  72. return self._security
  73. .. tip ::
  74. You can view the code so far here: `commit 2`_
  75. 9. Run the tests, and the following message will cause all security service
  76. tests to fail:
  77. .. code-block:: bash
  78. TypeError: Can't instantiate abstract class GCESecurityService with abstract
  79. methods key_pairs, security_groups
  80. The Abstract Base Classes are doing their job and flagging all methods that
  81. need to be implemented.
  82. 10. Since the security service simply provides organisational structure, and is
  83. a container for the key_pair and security_group service, we must next implement
  84. these services.
  85. .. code-block:: python
  86. from cloudbridge.cloud.base.services import BaseKeyPairService
  87. from cloudbridge.cloud.base.services import BaseSecurityGroupService
  88. from cloudbridge.cloud.base.services import BaseSecurityService
  89. class GCESecurityService(BaseSecurityService):
  90. def __init__(self, provider):
  91. super(GCESecurityService, self).__init__(provider)
  92. # Initialize provider services
  93. self._key_pairs = GCEKeyPairService(provider)
  94. self._security_groups = GCESecurityGroupService(provider)
  95. @property
  96. def key_pairs(self):
  97. return self._key_pairs
  98. @property
  99. def security_groups(self):
  100. return self._security_groups
  101. class GCEKeyPairService(BaseKeyPairService):
  102. def __init__(self, provider):
  103. super(GCEKeyPairService, self).__init__(provider)
  104. class GCESecurityGroupService(BaseSecurityGroupService):
  105. def __init__(self, provider):
  106. super(GCESecurityGroupService, self).__init__(provider)
  107. .. tip ::
  108. You can view the code so far here: `commit 3`_
  109. Once again, running the tests will complain of missing methods:
  110. .. code-block:: bash
  111. TypeError: Can't instantiate abstract class GCEKeyPairService with abstract
  112. methods create, find, get, list
  113. 11. Keep implementing the methods till the security service works, and the
  114. tests pass.
  115. .. note ::
  116. We start off by implementing the list keypairs method. Therefore, to obtain
  117. the keypair, we need to have a connection to the cloud provider. For this,
  118. we need to install the google sdk, and thereafter, to obtain the desired
  119. connection via the sdk. While the design and structure of that connection is
  120. up to the implementor, a general design we have followed is to have the
  121. cloud connection globally available within the provider.
  122. To add the sdk, we edit cloudbridge's main setup.py and list the dependencies.
  123. .. code-block:: python
  124. gce_reqs = ['google-api-python-client==1.4.2']
  125. full_reqs = base_reqs + aws_reqs + openstack_reqs + gce_reqs
  126. We will also register the provider in cloudbridge/factory.py's provider list.
  127. .. code-block:: python
  128. class ProviderList(object):
  129. AWS = 'aws'
  130. OPENSTACK = 'openstack'
  131. ...
  132. GCE = 'gce'
  133. .. tip ::
  134. You can view the code so far here: `commit 4`_
  135. 12. Thereafter, we create the actual connection through the sdk. In the case of
  136. GCE, we need a Compute API client object. We will make this connection
  137. available as a public property named gce_compute in the provider. We will then
  138. lazily initialize this connection.
  139. A full implementation of the KeyPair service can now be made in a provider specific
  140. manner.
  141. .. tip ::
  142. You can view the code so far here: `commit 5`_
  143. .. _commit 1: https://github.com/gvlproject/cloudbridge/commit/54c67e93a3cd9d51e7d2b1195ebf4e257d165297
  144. .. _commit 2: https://github.com/gvlproject/cloudbridge/commit/82c0244aa4229ae0aecfe40d769eb93b06470dc7
  145. .. _commit 3: https://github.com/gvlproject/cloudbridge/commit/e90a7f6885814a3477cd0b38398d62af64f91093
  146. .. _commit 4: https://github.com/gvlproject/cloudbridge/commit/2d5c14166a538d320e54eed5bc3fa04997828715
  147. .. _commit 5: https://github.com/gvlproject/cloudbridge/commit/98c9cf578b672867ee503027295f9d901411e496