provider.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. """
  2. Provider implementation based on OpenStack Python clients for OpenStack
  3. compatible clouds.
  4. """
  5. import os
  6. from cinderclient import client as cinder_client
  7. from keystoneclient import client as keystone_client
  8. from keystoneclient import session
  9. from neutronclient.v2_0 import client as neutron_client
  10. from novaclient import client as nova_client
  11. from novaclient import shell as nova_shell
  12. from swiftclient import client as swift_client
  13. from cloudbridge.cloud.base import BaseCloudProvider
  14. from .services import OpenStackBlockStoreService
  15. from .services import OpenStackComputeService
  16. from .services import OpenStackNetworkService
  17. from .services import OpenStackObjectStoreService
  18. from .services import OpenStackSecurityService
  19. class OpenStackCloudProvider(BaseCloudProvider):
  20. PROVIDER_ID = 'openstack'
  21. def __init__(self, config):
  22. super(OpenStackCloudProvider, self).__init__(config)
  23. self.cloud_type = 'openstack'
  24. # Initialize cloud connection fields
  25. self.username = self._get_config_value(
  26. 'os_username', os.environ.get('OS_USERNAME', None))
  27. self.password = self._get_config_value(
  28. 'os_password', os.environ.get('OS_PASSWORD', None))
  29. self.tenant_name = self._get_config_value(
  30. 'os_tenant_name', os.environ.get('OS_TENANT_NAME', None))
  31. self.auth_url = self._get_config_value(
  32. 'os_auth_url', os.environ.get('OS_AUTH_URL', None))
  33. self.region_name = self._get_config_value(
  34. 'os_region_name', os.environ.get('OS_REGION_NAME', None))
  35. self.project_name = self._get_config_value(
  36. 'os_project_name', os.environ.get('OS_PROJECT_NAME', None))
  37. self.project_domain_name = self._get_config_value(
  38. 'os_project_domain_name',
  39. os.environ.get('OS_PROJECT_DOMAIN_NAME', None))
  40. self.user_domain_name = self._get_config_value(
  41. 'os_user_domain_name', os.environ.get('OS_USER_DOMAIN_NAME', None))
  42. self.identity_api_version = self._get_config_value(
  43. 'os_identity_api_version',
  44. os.environ.get('OS_IDENTITY_API_VERSION', None))
  45. # Allow individual service connections to have their own values but
  46. # default to a the ones defined above.
  47. self.swift_username = self._get_config_value(
  48. 'os_swift_username',
  49. os.environ.get('OS_SWIFT_USERNAME', self.username))
  50. self.swift_password = self._get_config_value(
  51. 'os_swift_password',
  52. os.environ.get('OS_SWIFT_PASSWORD', self.password))
  53. self.swift_tenant_name = self._get_config_value(
  54. 'os_swift_tenant_name',
  55. os.environ.get('OS_SWIFT_TENANT_NAME', self.tenant_name))
  56. self.swift_auth_url = self._get_config_value(
  57. 'os_swift_auth_url',
  58. os.environ.get('OS_SWIFT_AUTH_URL', self.auth_url))
  59. self.swift_region_name = self._get_config_value(
  60. 'os_swift_region_name',
  61. os.environ.get('OS_SWIFT_REGION_NAME', self.region_name))
  62. # Service connections, lazily initialized
  63. self._nova = None
  64. self._keystone = None
  65. self._glance = None
  66. self._cinder = None
  67. self._swift = None
  68. self._neutron = None
  69. # Initialize provider services
  70. self._compute = OpenStackComputeService(self)
  71. self._network = OpenStackNetworkService(self)
  72. self._security = OpenStackSecurityService(self)
  73. self._block_store = OpenStackBlockStoreService(self)
  74. self._object_store = OpenStackObjectStoreService(self)
  75. @property
  76. def nova(self):
  77. if not self._nova:
  78. self._nova = self._connect_nova()
  79. return self._nova
  80. @property
  81. def keystone(self):
  82. if not self._keystone:
  83. self._keystone = self._connect_keystone()
  84. return self._keystone
  85. @property
  86. def _keystone_version(self):
  87. """
  88. Return the numeric version of remote Keystone server.
  89. :rtype: ``int``
  90. :return: Keystone version as an int (currently, 2 or 3).
  91. """
  92. ks_version = keystone_client.Client(auth_url=self.auth_url).version
  93. if ks_version == 'v3':
  94. return 3
  95. return 2
  96. @property
  97. def _keystone_session(self):
  98. """
  99. Connect to Keystone and return a session object.
  100. :rtype: :class:`keystoneclient.session.Session`
  101. :return: A Keystone session object.
  102. """
  103. def connect_v2():
  104. from keystoneclient.auth.identity import Password as Password_v2
  105. auth = Password_v2(self.auth_url, username=self.username,
  106. password=self.password,
  107. tenant_name=self.tenant_name)
  108. return session.Session(auth=auth)
  109. def connect_v3():
  110. from keystoneclient.auth.identity.v3 import Password as Password_v3
  111. auth = Password_v3(auth_url=self.auth_url,
  112. username=self.username,
  113. password=self.password,
  114. user_domain_name=self.user_domain_name,
  115. project_domain_name=self.project_domain_name,
  116. project_name=self.project_name)
  117. return session.Session(auth=auth)
  118. return connect_v3() if self._keystone_version == 3 else connect_v2()
  119. # @property
  120. # def glance(self):
  121. # if not self._glance:
  122. # self._glance = self._connect_glance()
  123. # return self._glance
  124. @property
  125. def cinder(self):
  126. if not self._cinder:
  127. self._cinder = self._connect_cinder()
  128. return self._cinder
  129. @property
  130. def swift(self):
  131. if not self._swift:
  132. self._swift = self._connect_swift()
  133. return self._swift
  134. @property
  135. def neutron(self):
  136. if not self._neutron:
  137. self._neutron = self._connect_neutron()
  138. return self._neutron
  139. @property
  140. def compute(self):
  141. return self._compute
  142. @property
  143. def network(self):
  144. return self._network
  145. @property
  146. def security(self):
  147. return self._security
  148. @property
  149. def block_store(self):
  150. return self._block_store
  151. @property
  152. def object_store(self):
  153. return self._object_store
  154. def _connect_nova(self):
  155. return self._connect_nova_region(self.region_name)
  156. def _connect_nova_region(self, region_name):
  157. """
  158. Get an OpenStack Nova (compute) client object for the given cloud.
  159. """
  160. def connect_pwd():
  161. """
  162. Connect using username and password parameters.
  163. """
  164. nova = nova_client.Client(
  165. api_version, username=self.username, api_key=self.password,
  166. project_id=self.tenant_name, auth_url=self.auth_url,
  167. region_name=region_name, service_name=service_name,
  168. http_log_debug=True if self.config.debug_mode else False)
  169. nova.authenticate()
  170. return nova
  171. def connect_sess():
  172. """
  173. Connect using a Keystone session object.
  174. """
  175. return nova_client.Client(
  176. api_version, session=self._keystone_session,
  177. service_name=service_name,
  178. http_log_debug=True if self.config.debug_mode else False)
  179. api_version = self._get_config_value(
  180. 'os_compute_api_version',
  181. os.environ.get('OS_COMPUTE_API_VERSION', 2))
  182. service_name = self._get_config_value(
  183. 'nova_service_name',
  184. os.environ.get('NOVA_SERVICE_NAME', None))
  185. if self.config.debug_mode:
  186. nova_shell.OpenStackComputeShell().setup_debugging(True)
  187. return connect_sess() if self._keystone_version == 3 else connect_pwd()
  188. def _connect_keystone(self):
  189. """
  190. Get an OpenStack Keystone (identity) client object for the given cloud.
  191. """
  192. def connect_v2():
  193. # Wow, the internal keystoneV2 implementation is terribly buggy. It
  194. # needs both a separate Session object and the username, password
  195. # again for things to work correctly. Plus, a manual call to
  196. # authenticate() is also required if the service catalog needs
  197. # to be queried.
  198. keystone = keystone_client.Client(
  199. session=self._keystone_session,
  200. auth_url=self.auth_url,
  201. username=self.username,
  202. password=self.password,
  203. tenant_name=self.tenant_name,
  204. region_name=self.region_name)
  205. keystone.authenticate()
  206. return keystone
  207. def connect_v3():
  208. return keystone_client.Client(session=self._keystone_session,
  209. auth_url=self.auth_url)
  210. return connect_v3() if self._keystone_version == 3 else connect_v2()
  211. def _connect_cinder(self):
  212. """
  213. Get an OpenStack Cinder (block storage) client object for the given
  214. cloud.
  215. """
  216. def connect_pwd():
  217. """
  218. Connect using username and password parameters.
  219. """
  220. return cinder_client.Client(
  221. api_version, username=self.username, api_key=self.password,
  222. project_id=self.tenant_name, auth_url=self.auth_url)
  223. def connect_sess():
  224. """
  225. Connect using a Keystone session object.
  226. """
  227. return cinder_client.Client(
  228. api_version, session=self._keystone_session)
  229. api_version = self._get_config_value(
  230. 'os_volume_api_version',
  231. os.environ.get('OS_VOLUME_API_VERSION', 2))
  232. return connect_sess() if self._keystone_version == 3 else connect_pwd()
  233. # def _connect_glance(self):
  234. # """
  235. # Get an OpenStack Glance (VM images) client object for the given
  236. # cloud.
  237. # """
  238. # api_version = self._get_config_value(
  239. # 'os_image_api_version',
  240. # os.environ.get('OS_IMAGE_API_VERSION', 1))
  241. #
  242. # return glance_client.Client(version=api_version,
  243. # session=self.keystone.session)
  244. def _connect_swift(self):
  245. """
  246. Get an OpenStack Swift (object store) client object for the given
  247. cloud.
  248. """
  249. def connect_v2():
  250. os_options = {'region_name': self.swift_region_name}
  251. return swift_client.Connection(
  252. authurl=self.swift_auth_url, auth_version='2',
  253. user=self.swift_username, key=self.swift_password,
  254. tenant_name=self.swift_tenant_name,
  255. os_options=os_options)
  256. def connect_v3():
  257. os_options = {'region_name': self.swift_region_name,
  258. 'user_domain_name': self.user_domain_name,
  259. 'project_domain_name': self.project_domain_name,
  260. 'project_name': self.project_name}
  261. return swift_client.Connection(
  262. authurl=self.swift_auth_url, auth_version='3',
  263. user=self.swift_username, key=self.swift_password,
  264. os_options=os_options)
  265. return connect_v3() if self._keystone_version == 3 else connect_v2()
  266. def _connect_neutron(self):
  267. """
  268. Get an OpenStack Neutron (networking) client object for the given
  269. cloud.
  270. """
  271. def connect_pwd():
  272. """
  273. Connect using username and password parameters.
  274. """
  275. return neutron_client.Client(
  276. username=self.username, password=self.password,
  277. tenant_name=self.tenant_name, auth_url=self.auth_url)
  278. def connect_sess():
  279. """
  280. Connect using a Keystone session object.
  281. """
  282. return neutron_client.Client(session=self._keystone_session)
  283. return connect_sess() if self._keystone_version == 3 else connect_pwd()