mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #38647 from gtmanfred/nova
Allow novaclient to use keystoneauth1 sessions for authentication
This commit is contained in:
commit
7b850d472d
2 changed files with 133 additions and 1 deletions
|
@ -48,6 +48,25 @@ examples could be set up in the cloud configuration at
|
|||
driver: nova
|
||||
userdata_file: /tmp/userdata.txt
|
||||
|
||||
To use keystoneauth1 instead of keystoneclient, include the `use_keystoneauth`
|
||||
option in the provider config.
|
||||
|
||||
.. note:: this is required to use keystone v3 as for authentication.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my-openstack-config:
|
||||
use_keystoneauth: True
|
||||
identity_url: 'https://controller:5000/v3'
|
||||
auth_version: 3
|
||||
compute_name: nova
|
||||
compute_region: RegionOne
|
||||
service_type: compute
|
||||
tenant: admin
|
||||
user: admin
|
||||
password: passwordgoeshere
|
||||
driver: nova
|
||||
|
||||
For local installations that only use private IP address ranges, the
|
||||
following option may be useful. Using the old syntax:
|
||||
|
||||
|
@ -266,6 +285,7 @@ def get_conn():
|
|||
kwargs['project_id'] = vm_['tenant']
|
||||
kwargs['auth_url'] = vm_['identity_url']
|
||||
kwargs['region_name'] = vm_['compute_region']
|
||||
kwargs['use_keystoneauth'] = vm_['use_keystoneauth']
|
||||
|
||||
if 'password' in vm_:
|
||||
kwargs['password'] = vm_['password']
|
||||
|
|
|
@ -6,9 +6,9 @@ Nova class
|
|||
# Import Python libs
|
||||
from __future__ import absolute_import, with_statement
|
||||
from distutils.version import LooseVersion
|
||||
import time
|
||||
import inspect
|
||||
import logging
|
||||
import time
|
||||
|
||||
# Import third party libs
|
||||
import salt.ext.six as six
|
||||
|
@ -26,6 +26,14 @@ try:
|
|||
HAS_NOVA = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
HAS_KEYSTONEAUTH = False
|
||||
try:
|
||||
import keystoneauth1.loading
|
||||
import keystoneauth1.session
|
||||
HAS_KEYSTONEAUTH = True
|
||||
except ImportError:
|
||||
pass
|
||||
# pylint: enable=import-error
|
||||
|
||||
# Import salt libs
|
||||
|
@ -164,6 +172,15 @@ def get_entry(dict_, key, value, raise_error=True):
|
|||
return {}
|
||||
|
||||
|
||||
def get_entry_multi(dict_, pairs, raise_error=True):
|
||||
for entry in dict_:
|
||||
if all([entry[key] == value for key, value in pairs]):
|
||||
return entry
|
||||
if raise_error is True:
|
||||
raise SaltCloudSystemExit('Unable to find {0} in {1}.'.format(pairs, dict_))
|
||||
return {}
|
||||
|
||||
|
||||
def sanatize_novaclient(kwargs):
|
||||
variables = (
|
||||
'username', 'api_key', 'project_id', 'auth_url', 'insecure',
|
||||
|
@ -196,11 +213,79 @@ class SaltNova(object):
|
|||
region_name=None,
|
||||
password=None,
|
||||
os_auth_plugin=None,
|
||||
use_keystoneauth=False,
|
||||
**kwargs
|
||||
):
|
||||
'''
|
||||
Set up nova credentials
|
||||
'''
|
||||
if all([use_keystoneauth, HAS_KEYSTONEAUTH]):
|
||||
self._new_init(username=username,
|
||||
project_id=project_id,
|
||||
auth_url=auth_url,
|
||||
region_name=region_name,
|
||||
password=password,
|
||||
os_auth_plugin=os_auth_plugin,
|
||||
**kwargs)
|
||||
else:
|
||||
self._old_init(username=username,
|
||||
project_id=project_id,
|
||||
auth_url=auth_url,
|
||||
region_name=region_name,
|
||||
password=password,
|
||||
os_auth_plugin=os_auth_plugin,
|
||||
**kwargs)
|
||||
|
||||
def _new_init(self, username, project_id, auth_url, region_name, password, os_auth_plugin, auth=None, **kwargs):
|
||||
if auth is None:
|
||||
auth = {}
|
||||
|
||||
loader = keystoneauth1.loading.get_plugin_loader(os_auth_plugin or 'password')
|
||||
|
||||
self.client_kwargs = kwargs.copy()
|
||||
self.kwargs = auth.copy()
|
||||
if not self.extensions:
|
||||
if hasattr(OpenStackComputeShell, '_discover_extensions'):
|
||||
self.extensions = OpenStackComputeShell()._discover_extensions('2.0')
|
||||
else:
|
||||
self.extensions = client.discover_extensions('2.0')
|
||||
for extension in self.extensions:
|
||||
extension.run_hooks('__pre_parse_args__')
|
||||
self.client_kwargs['extensions'] = self.extensions
|
||||
|
||||
self.kwargs['username'] = username
|
||||
self.kwargs['project_name'] = project_id
|
||||
self.kwargs['auth_url'] = auth_url
|
||||
self.kwargs['password'] = password
|
||||
if auth_url.endswith('3'):
|
||||
self.kwargs['user_domain_name'] = kwargs.get('user_domain_name', 'default')
|
||||
self.kwargs['project_domain_name'] = kwargs.get('project_domain_name', 'default')
|
||||
|
||||
self.client_kwargs['region_name'] = region_name
|
||||
self.client_kwargs['service_type'] = 'compute'
|
||||
|
||||
if hasattr(self, 'extensions'):
|
||||
# needs an object, not a dictionary
|
||||
self.kwargstruct = KwargsStruct(**self.client_kwargs)
|
||||
for extension in self.extensions:
|
||||
extension.run_hooks('__post_parse_args__', self.kwargstruct)
|
||||
self.client_kwargs = self.kwargstruct.__dict__
|
||||
|
||||
# Requires novaclient version >= 2.6.1
|
||||
self.version = str(kwargs.get('version', 2))
|
||||
|
||||
self.client_kwargs = sanatize_novaclient(self.client_kwargs)
|
||||
options = loader.load_from_options(**self.kwargs)
|
||||
self.session = keystoneauth1.session.Session(auth=options)
|
||||
conn = client.Client(version=self.version, session=self.session, **self.client_kwargs)
|
||||
self.kwargs['auth_token'] = conn.client.session.get_token()
|
||||
self.catalog = conn.client.session.get('/auth/catalog', endpoint_filter={'service_type': 'identity'}).json().get('catalog', [])
|
||||
if conn.client.get_endpoint(service_type='identity').endswith('v3'):
|
||||
self._v3_setup(region_name)
|
||||
else:
|
||||
self._v2_setup(region_name)
|
||||
|
||||
def _old_init(self, username, project_id, auth_url, region_name, password, os_auth_plugin, **kwargs):
|
||||
self.kwargs = kwargs.copy()
|
||||
if not self.extensions:
|
||||
if hasattr(OpenStackComputeShell, '_discover_extensions'):
|
||||
|
@ -254,6 +339,33 @@ class SaltNova(object):
|
|||
self.kwargs['auth_token'] = conn.client.auth_token
|
||||
self.catalog = conn.client.service_catalog.catalog['access']['serviceCatalog']
|
||||
|
||||
self._v2_setup(region_name)
|
||||
|
||||
def _v3_setup(self, region_name):
|
||||
if region_name is not None:
|
||||
servers_endpoints = get_entry(self.catalog, 'type', 'compute')['endpoints']
|
||||
self.kwargs['bypass_url'] = get_entry_multi(
|
||||
servers_endpoints,
|
||||
[('region', region_name), ('interface', 'public')]
|
||||
)['url']
|
||||
|
||||
self.compute_conn = client.Client(version=self.version, session=self.session, **self.client_kwargs)
|
||||
|
||||
volume_endpoints = get_entry(self.catalog, 'type', 'volume', raise_error=False).get('endpoints', {})
|
||||
if volume_endpoints:
|
||||
if region_name is not None:
|
||||
self.kwargs['bypass_url'] = get_entry_multi(
|
||||
volume_endpoints,
|
||||
[('region', region_name), ('interface', 'public')]
|
||||
)['url']
|
||||
|
||||
self.volume_conn = client.Client(version=self.version, session=self.session, **self.client_kwargs)
|
||||
if hasattr(self, 'extensions'):
|
||||
self.expand_extensions()
|
||||
else:
|
||||
self.volume_conn = None
|
||||
|
||||
def _v2_setup(self, region_name):
|
||||
if region_name is not None:
|
||||
servers_endpoints = get_entry(self.catalog, 'type', 'compute')['endpoints']
|
||||
self.kwargs['bypass_url'] = get_entry(
|
||||
|
|
Loading…
Add table
Reference in a new issue