| # -*- coding: utf-8 -*- |
| ''' |
| Module for handling openstack keystone calls. |
| |
| :optdepends: - keystoneclient Python adapter |
| :configuration: This module is not usable until the following are specified |
| either in a pillar or in the minion's config file: |
| |
| .. code-block:: yaml |
| |
| keystone.user: admin |
| keystone.password: verybadpass |
| keystone.tenant: admin |
| keystone.tenant_id: f80919baedab48ec8931f200c65a50df |
| keystone.auth_url: 'http://127.0.0.1:5000/v2.0/' |
| |
| OR (for token based authentication) |
| |
| .. code-block:: yaml |
| |
| keystone.token: 'ADMIN' |
| keystone.endpoint: 'http://127.0.0.1:35357/v2.0' |
| |
| If configuration for multiple openstack accounts is required, they can be |
| set up as different configuration profiles. For example: |
| |
| .. code-block:: yaml |
| |
| openstack1: |
| keystone.user: admin |
| keystone.password: verybadpass |
| keystone.tenant: admin |
| keystone.tenant_id: f80919baedab48ec8931f200c65a50df |
| keystone.auth_url: 'http://127.0.0.1:5000/v2.0/' |
| |
| openstack2: |
| keystone.user: admin |
| keystone.password: verybadpass |
| keystone.tenant: admin |
| keystone.tenant_id: f80919baedab48ec8931f200c65a50df |
| keystone.auth_url: 'http://127.0.0.2:5000/v2.0/' |
| |
| openstack_version3: |
| keystone.user: admin |
| keystone.password: verybadpass |
| keystone.tenant: admin |
| keystone.tenant_id: f80919baedab48ec8931f200c65a50df |
| keystone.auth_url: 'http://127.0.0.2:5000/v3' |
| |
| openstack_nonversioned: |
| keystone.user: admin |
| keystone.password: verybadpass |
| keystone.tenant: admin |
| keystone.tenant_id: f80919baedab48ec8931f200c65a50df |
| keystone.auth_url: 'http://127.0.0.2:5000' |
| |
| With this configuration in place, any of the keystone functions can make use |
| of a configuration profile by declaring it explicitly. |
| For example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_list profile=openstack1 |
| ''' |
| |
| # Import Python libs |
| from __future__ import absolute_import |
| import logging |
| |
| # Import Salt Libs |
| import salt.utils.http |
| |
| # Import 3rd-party libs |
| from salt.ext import six |
| HAS_KEYSTONE = False |
| try: |
| # pylint: disable=import-error |
| from keystoneclient import client |
| from keystoneclient.v2_0 import client as keystoneclient_v2 |
| import keystoneclient.exceptions |
| HAS_KEYSTONE = True |
| from keystoneclient.v3 import client as keystoneclient_v3 |
| from keystoneclient import discover |
| from keystoneauth1 import session |
| from keystoneauth1.identity import generic |
| from keystoneauth1 import token_endpoint |
| # pylint: enable=import-error |
| except ImportError: |
| pass |
| |
| log = logging.getLogger(__name__) |
| |
| |
| def __virtual__(): |
| ''' |
| Only load this module if keystone |
| is installed on this minion. |
| ''' |
| if HAS_KEYSTONE: |
| return 'keystoneng' |
| return (False, 'keystone execution module cannot be loaded: keystoneclient python library not available.') |
| |
| __opts__ = {} |
| |
| |
| def _get_kwargs(profile=None, **connection_args): |
| ''' |
| get connection args |
| ''' |
| if profile: |
| prefix = profile + ":keystone." |
| else: |
| prefix = "keystone." |
| |
| def get(key, default=None): |
| ''' |
| look in connection_args first, then default to config file |
| ''' |
| return connection_args.get('connection_' + key, |
| __salt__['config.get'](prefix + key, default)) |
| |
| user = get('user', 'admin') |
| password = get('password', 'ADMIN') |
| tenant = get('tenant', 'admin') |
| tenant_id = get('tenant_id') |
| auth_url = get('auth_url', 'http://127.0.0.1:5000/v2.0/') |
| insecure = get('insecure', False) |
| token = get('token') |
| endpoint = get('endpoint', 'http://127.0.0.1:5000/v2.0') |
| if token: |
| kwargs = {'token': token, |
| 'endpoint': endpoint} |
| else: |
| kwargs = {'username': user, |
| 'password': password, |
| 'tenant_name': tenant, |
| 'tenant_id': tenant_id, |
| 'auth_url': auth_url} |
| # 'insecure' keyword not supported by all v2.0 keystone clients |
| # this ensures it's only passed in when defineda |
| if get('user_id'): kwargs['user_id']=get('user_id') |
| if get('user_domain_id'): kwargs['user_domain_id']=get('user_domain_id') |
| if get('domain_id'): kwargs['domain_id']=get('domain_id') |
| if get('domain_name'): kwargs['domain_name']=get('domain_name') |
| if get('project_id'): kwargs['project_id']=get('project_id') |
| if get('project_name'): kwargs['project_name']=get('project_name') |
| if get('project_domain_id'): kwargs['project_domain_id']=get('project_domain_id') |
| if get('region_name'): kwargs['region_name']=get('region_name') |
| if get('endpoint'): kwargs['endpoint']=get('endpoint') |
| if get('timeout'): kwargs['timeout']=get('timeout') |
| if get('user_domain_name'): kwargs['user_domain_name']=get('user_domain_name') |
| if get('project_domain_name'): kwargs['project_domain_name']=get('project_domain_name') |
| kwargs['insecure'] = get('insecure', False) |
| if get('version'): |
| version_list = str(get('version')).split('.') |
| if len(version_list) == 2: |
| kwargs['version'] = (version_list[0], version_list[1]) |
| else: |
| kwargs['version'] = (version_list[0]) |
| |
| return kwargs |
| |
| |
| def _client_version(keystone_client): |
| ''' |
| Returns keystone client version |
| ''' |
| if isinstance(keystone_client, keystoneclient_v3.Client): |
| return 3 |
| if isinstance(keystone_client, keystoneclient_v2.Client): |
| return 2 |
| return None |
| |
| |
| def _project_mgr(keystone_client): |
| ''' |
| Returns keystoneclient.v3.Client.projects object if keystone client version > 2 |
| or keystoneclient.v2_0.Client.tenants for other cases. |
| ''' |
| if _client_version(keystone_client) > 2: |
| return keystone_client.projects |
| return keystone_client.tenants |
| |
| |
| def api_version(profile=None, **connection_args): |
| ''' |
| Returns the API version derived from endpoint's response. |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.api_version |
| ''' |
| keystone_client = auth(profile, **connection_args) |
| if isinstance(keystone_client, keystoneclient_v3.Client): |
| return 3 |
| if isinstance(keystone_client, keystoneclient_v2.Client): |
| return 2 |
| return None |
| |
| |
| def auth(profile=None, **connection_args): |
| ''' |
| Set up keystone credentials. Only intended to be used within Keystone-enabled modules. |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.auth |
| ''' |
| kwargs = _get_kwargs(profile=profile, **connection_args) |
| if 'token' in kwargs: |
| auth = token_endpoint.Token(endpoint=kwargs['endpoint'], token=kwargs['token']) |
| else: |
| # keystoneauth1 Password class does not accept some args. Therefore remove it from args for auth. |
| auth_connection_args=kwargs.copy() |
| auth_connection_args.pop('region_name', None) |
| auth_connection_args.pop('version', None) |
| auth_connection_args.pop('insecure', None) |
| auth = generic.Password(**auth_connection_args) |
| if 'insecure' in kwargs: |
| certs_verify = False |
| else: |
| certs_verify = True |
| sess = session.Session(auth=auth, verify=certs_verify) |
| keystone_client=client.Client(session=sess, **kwargs) |
| return keystone_client |
| |
| |
| def ec2_credentials_create(user_id=None, name=None, |
| tenant_id=None, tenant=None, |
| profile=None, **connection_args): |
| ''' |
| Create EC2-compatible credentials for user per tenant |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.ec2_credentials_create name=admin tenant=admin |
| |
| salt '*' keystone.ec2_credentials_create \ |
| user_id=c965f79c4f864eaaa9c3b41904e67082 \ |
| tenant_id=722787eb540849158668370dc627ec5f |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if name: |
| user_id = user_get(name=name, profile=profile, |
| **connection_args)[name]['id'] |
| if not user_id: |
| return {'Error': 'Could not resolve User ID'} |
| |
| if tenant: |
| tenant_id = tenant_get(name=tenant, profile=profile, |
| **connection_args)[tenant]['id'] |
| if not tenant_id: |
| return {'Error': 'Could not resolve Tenant ID'} |
| |
| newec2 = kstone.ec2.create(user_id, tenant_id) |
| return {'access': newec2.access, |
| 'secret': newec2.secret, |
| 'tenant_id': newec2.tenant_id, |
| 'user_id': newec2.user_id} |
| |
| |
| def ec2_credentials_delete(user_id=None, name=None, access_key=None, |
| profile=None, **connection_args): |
| ''' |
| Delete EC2-compatible credentials |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.ec2_credentials_delete \ |
| 860f8c2c38ca4fab989f9bc56a061a64 access_key=5f66d2f24f604b8bb9cd28886106f442 |
| |
| salt '*' keystone.ec2_credentials_delete name=admin \ |
| access_key=5f66d2f24f604b8bb9cd28886106f442 |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if name: |
| user_id = user_get(name=name, profile=None, **connection_args)[name]['id'] |
| if not user_id: |
| return {'Error': 'Could not resolve User ID'} |
| kstone.ec2.delete(user_id, access_key) |
| return 'ec2 key "{0}" deleted under user id "{1}"'.format(access_key, |
| user_id) |
| |
| |
| def ec2_credentials_get(user_id=None, name=None, access=None, |
| profile=None, **connection_args): |
| ''' |
| Return ec2_credentials for a user (keystone ec2-credentials-get) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.ec2_credentials_get c965f79c4f864eaaa9c3b41904e67082 access=722787eb540849158668370 |
| salt '*' keystone.ec2_credentials_get user_id=c965f79c4f864eaaa9c3b41904e67082 access=722787eb540849158668370 |
| salt '*' keystone.ec2_credentials_get name=nova access=722787eb540849158668370dc627ec5f |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| if name: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| if not access: |
| return {'Error': 'Access key is required'} |
| ec2_credentials = kstone.ec2.get(user_id=user_id, access=access, |
| profile=profile, **connection_args) |
| ret[ec2_credentials.user_id] = {'user_id': ec2_credentials.user_id, |
| 'tenant': ec2_credentials.tenant_id, |
| 'access': ec2_credentials.access, |
| 'secret': ec2_credentials.secret} |
| return ret |
| |
| |
| def ec2_credentials_list(user_id=None, name=None, profile=None, |
| **connection_args): |
| ''' |
| Return a list of ec2_credentials for a specific user (keystone ec2-credentials-list) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.ec2_credentials_list 298ce377245c4ec9b70e1c639c89e654 |
| salt '*' keystone.ec2_credentials_list user_id=298ce377245c4ec9b70e1c639c89e654 |
| salt '*' keystone.ec2_credentials_list name=jack |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| if name: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| for ec2_credential in kstone.ec2.list(user_id): |
| ret[ec2_credential.user_id] = {'user_id': ec2_credential.user_id, |
| 'tenant_id': ec2_credential.tenant_id, |
| 'access': ec2_credential.access, |
| 'secret': ec2_credential.secret} |
| return ret |
| |
| |
| def endpoint_get(service, region=None, profile=None, interface=None, **connection_args): |
| ''' |
| Return a specific endpoint (keystone endpoint-get) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt 'v2' keystone.endpoint_get nova [region=RegionOne] |
| |
| salt 'v3' keystone.endpoint_get nova interface=admin [region=RegionOne] |
| ''' |
| auth(profile, **connection_args) |
| services = service_list(profile, **connection_args) |
| if service not in services: |
| return {'Error': 'Could not find the specified service'} |
| service_id = services[service]['id'] |
| endpoints = endpoint_list(profile, **connection_args) |
| |
| e = [_f for _f in [e |
| if e['service_id'] == service_id and |
| (e['region'] == region if region else True) and |
| (e['interface'] == interface if interface else True) |
| else None for e in endpoints.values()] if _f] |
| if len(e) > 1: |
| return {'Error': 'Multiple endpoints found ({0}) for the {1} service. Please specify region.'.format(e, service)} |
| if len(e) == 1: |
| return e[0] |
| return {'Error': 'Could not find endpoint for the specified service'} |
| |
| |
| def endpoint_list(profile=None, **connection_args): |
| ''' |
| Return a list of available endpoints (keystone endpoints-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.endpoint_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| |
| for endpoint in kstone.endpoints.list(): |
| ret[endpoint.id] = dict((value, getattr(endpoint, value)) for value in dir(endpoint) |
| if not value.startswith('_') and |
| isinstance(getattr(endpoint, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def endpoint_create(service, publicurl=None, internalurl=None, adminurl=None, |
| region=None, profile=None, url=None, interface=None, **connection_args): |
| ''' |
| Create an endpoint for an Openstack service |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt 'v2' keystone.endpoint_create nova 'http://public/url' 'http://internal/url' 'http://adminurl/url' region |
| |
| salt 'v3' keystone.endpoint_create nova url='http://public/url' interface='public' region='RegionOne' |
| ''' |
| kstone = auth(profile, **connection_args) |
| keystone_service = service_get(name=service, profile=profile, |
| **connection_args) |
| if not keystone_service or 'Error' in keystone_service: |
| return {'Error': 'Could not find the specified service'} |
| |
| if _client_version(kstone) > 2: |
| kstone.endpoints.create(service=keystone_service[service]['id'], |
| region_id=region, |
| url=url, |
| interface=interface) |
| else: |
| kstone.endpoints.create(region=region, |
| service_id=keystone_service[service]['id'], |
| publicurl=publicurl, |
| adminurl=adminurl, |
| internalurl=internalurl) |
| return endpoint_get(service, region, profile, interface, **connection_args) |
| |
| |
| def endpoint_delete(service, region=None, profile=None, interface=None, **connection_args): |
| ''' |
| Delete endpoints of an Openstack service |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt 'v2' keystone.endpoint_delete nova [region=RegionOne] |
| |
| salt 'v3' keystone.endpoint_delete nova interface=admin [region=RegionOne] |
| ''' |
| kstone = auth(profile, **connection_args) |
| endpoint = endpoint_get(service, region, profile, interface, **connection_args) |
| if not endpoint or 'Error' in endpoint: |
| return {'Error': 'Could not find any endpoints for the service'} |
| kstone.endpoints.delete(endpoint['id']) |
| endpoint = endpoint_get(service, region, profile, interface, **connection_args) |
| if not endpoint or 'Error' in endpoint: |
| return True |
| |
| |
| def role_create(name, profile=None, **connection_args): |
| ''' |
| Create a named role. |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.role_create admin |
| ''' |
| |
| kstone = auth(profile, **connection_args) |
| if 'Error' not in role_get(name=name, profile=profile, **connection_args): |
| return {'Error': 'Role "{0}" already exists'.format(name)} |
| kstone.roles.create(name) |
| return role_get(name=name, profile=profile, **connection_args) |
| |
| |
| def role_delete(role_id=None, name=None, profile=None, |
| **connection_args): |
| ''' |
| Delete a role (keystone role-delete) |
| |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.role_delete c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.role_delete role_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.role_delete name=admin |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if name: |
| for role in kstone.roles.list(): |
| if role.name == name: |
| role_id = role.id |
| break |
| if not role_id: |
| return {'Error': 'Unable to resolve role id'} |
| |
| role = kstone.roles.get(role_id) |
| kstone.roles.delete(role) |
| |
| ret = 'Role ID {0} deleted'.format(role_id) |
| if name: |
| ret += ' ({0})'.format(name) |
| return ret |
| |
| |
| def role_get(role_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Return a specific roles (keystone role-get) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.role_get c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.role_get role_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.role_get name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| if name: |
| for role in kstone.roles.list(): |
| if role.name == name: |
| role_id = role.id |
| break |
| if not role_id: |
| return {'Error': 'Unable to resolve role id'} |
| role = kstone.roles.get(role_id) |
| |
| ret[role.name] = {'id': role.id, |
| 'name': role.name} |
| return ret |
| |
| |
| def role_list(profile=None, **connection_args): |
| ''' |
| Return a list of available roles (keystone role-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.role_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| for role in kstone.roles.list(): |
| ret[role.name] = dict((value, getattr(role, value)) for value in dir(role) |
| if not value.startswith('_') and |
| isinstance(getattr(role, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def service_create(name, service_type, description=None, profile=None, |
| **connection_args): |
| ''' |
| Add service to Keystone service catalog |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.service_create nova compute \ |
| 'OpenStack Compute Service' |
| ''' |
| kstone = auth(profile, **connection_args) |
| service = kstone.services.create(name, service_type, description=description) |
| return service_get(service.id, profile=profile, **connection_args) |
| |
| |
| def service_delete(service_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Delete a service from Keystone service catalog |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.service_delete c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.service_delete name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| if name: |
| service_id = service_get(name=name, profile=profile, |
| **connection_args)[name]['id'] |
| kstone.services.delete(service_id) |
| return 'Keystone service ID "{0}" deleted'.format(service_id) |
| |
| |
| def service_get(service_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Return a specific services (keystone service-get) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.service_get c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.service_get service_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.service_get name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| if name: |
| for service in kstone.services.list(): |
| if service.name == name: |
| service_id = service.id |
| break |
| if not service_id: |
| return {'Error': 'Unable to resolve service id'} |
| service = kstone.services.get(service_id) |
| ret[service.name] = dict((value, getattr(service, value)) for value in dir(service) |
| if not value.startswith('_') and |
| isinstance(getattr(service, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def service_list(profile=None, **connection_args): |
| ''' |
| Return a list of available services (keystone services-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.service_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| for service in kstone.services.list(): |
| ret[service.name] = dict((value, getattr(service, value)) for value in dir(service) |
| if not value.startswith('_') and |
| isinstance(getattr(service, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def tenant_create(name, description=None, enabled=True, profile=None, |
| **connection_args): |
| ''' |
| Create a keystone tenant |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_create nova description='nova tenant' |
| salt '*' keystone.tenant_create test enabled=False |
| ''' |
| kstone = auth(profile, **connection_args) |
| new = _project_mgr(kstone).create(name, description, enabled) |
| return tenant_get(new.id, profile=profile, **connection_args) |
| |
| |
| def project_create(name, domain, description=None, enabled=True, profile=None, |
| **connection_args): |
| ''' |
| Create a keystone project. |
| Overrides keystone tenant_create form api V2. For keystone api V3. |
| |
| .. versionadded:: 2016.11.0 |
| |
| name |
| The project name, which must be unique within the owning domain. |
| |
| domain |
| The domain name. |
| |
| description |
| The project description. |
| |
| enabled |
| Enables or disables the project. |
| |
| profile |
| Configuration profile - if configuration for multiple openstack accounts required. |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.project_create nova default description='Nova Compute Project' |
| salt '*' keystone.project_create test default enabled=False |
| ''' |
| kstone = auth(profile, **connection_args) |
| new = _project_mgr(kstone).create(name=name, domain=domain, |
| description=description, enabled=enabled) |
| return tenant_get(new.id, profile=profile, **connection_args) |
| |
| |
| def tenant_delete(tenant_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Delete a tenant (keystone tenant-delete) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_delete c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.tenant_delete tenant_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.tenant_delete name=demo |
| ''' |
| kstone = auth(profile, **connection_args) |
| if name: |
| for tenant in _project_mgr(kstone).list(): |
| if tenant.name == name: |
| tenant_id = tenant.id |
| break |
| if not tenant_id: |
| return {'Error': 'Unable to resolve tenant id'} |
| _project_mgr(kstone).delete(tenant_id) |
| ret = 'Tenant ID {0} deleted'.format(tenant_id) |
| if name: |
| |
| ret += ' ({0})'.format(name) |
| return ret |
| |
| |
| def project_delete(project_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Delete a project (keystone project-delete). |
| Overrides keystone tenant-delete form api V2. For keystone api V3 only. |
| |
| .. versionadded:: 2016.11.0 |
| |
| project_id |
| The project id. |
| |
| name |
| The project name. |
| |
| profile |
| Configuration profile - if configuration for multiple openstack accounts required. |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.project_delete c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.project_delete project_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.project_delete name=demo |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if _client_version(kstone) > 2: |
| return tenant_delete(tenant_id=project_id, name=name, profile=None, **connection_args) |
| else: |
| return False |
| |
| |
| def tenant_get(tenant_id=None, name=None, profile=None, |
| **connection_args): |
| ''' |
| Return a specific tenants (keystone tenant-get) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_get c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.tenant_get tenant_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.tenant_get name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| |
| if name: |
| for tenant in _project_mgr(kstone).list(): |
| if tenant.name == name: |
| tenant_id = tenant.id |
| break |
| if not tenant_id: |
| return {'Error': 'Unable to resolve tenant id'} |
| tenant = _project_mgr(kstone).get(tenant_id) |
| ret[tenant.name] = dict((value, getattr(tenant, value)) for value in dir(tenant) |
| if not value.startswith('_') and |
| isinstance(getattr(tenant, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def project_get(project_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Return a specific projects (keystone project-get) |
| Overrides keystone tenant-get form api V2. |
| For keystone api V3 only. |
| |
| .. versionadded:: 2016.11.0 |
| |
| project_id |
| The project id. |
| |
| name |
| The project name. |
| |
| profile |
| Configuration profile - if configuration for multiple openstack accounts required. |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.project_get c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.project_get project_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.project_get name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if _client_version(kstone) > 2: |
| return tenant_get(tenant_id=project_id, name=name, profile=None, **connection_args) |
| else: |
| return False |
| |
| |
| def tenant_list(profile=None, **connection_args): |
| ''' |
| Return a list of available tenants (keystone tenants-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| |
| for tenant in _project_mgr(kstone).list(): |
| ret[tenant.name] = dict((value, getattr(tenant, value)) for value in dir(tenant) |
| if not value.startswith('_') and |
| isinstance(getattr(tenant, value), (six.string_types, dict, bool))) |
| return ret |
| |
| |
| def project_list(profile=None, **connection_args): |
| ''' |
| Return a list of available projects (keystone projects-list). |
| Overrides keystone tenants-list form api V2. |
| For keystone api V3 only. |
| |
| .. versionadded:: 2016.11.0 |
| |
| profile |
| Configuration profile - if configuration for multiple openstack accounts required. |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.project_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if _client_version(kstone) > 2: |
| return tenant_list(profile, **connection_args) |
| else: |
| return False |
| |
| |
| def tenant_update(tenant_id=None, name=None, description=None, |
| enabled=None, profile=None, **connection_args): |
| ''' |
| Update a tenant's information (keystone tenant-update) |
| The following fields may be updated: name, description, enabled. |
| Can only update name if targeting by ID |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.tenant_update name=admin enabled=True |
| salt '*' keystone.tenant_update c965f79c4f864eaaa9c3b41904e67082 name=admin email=admin@domain.com |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if not tenant_id: |
| for tenant in _project_mgr(kstone).list(): |
| if tenant.name == name: |
| tenant_id = tenant.id |
| break |
| if not tenant_id: |
| return {'Error': 'Unable to resolve tenant id'} |
| |
| tenant = _project_mgr(kstone).get(tenant_id) |
| if not name: |
| name = tenant.name |
| if not description: |
| description = tenant.description |
| if enabled is None: |
| enabled = tenant.enabled |
| updated = _project_mgr(kstone).update(tenant_id, name=name, description=description, enabled=enabled) |
| |
| return dict((value, getattr(updated, value)) for value in dir(updated) |
| if not value.startswith('_') and |
| isinstance(getattr(updated, value), (six.string_types, dict, bool))) |
| |
| |
| def project_update(project_id=None, name=None, description=None, |
| enabled=None, profile=None, **connection_args): |
| ''' |
| Update a tenant's information (keystone project-update) |
| The following fields may be updated: name, description, enabled. |
| Can only update name if targeting by ID |
| |
| Overrides keystone tenant_update form api V2. |
| For keystone api V3 only. |
| |
| .. versionadded:: 2016.11.0 |
| |
| project_id |
| The project id. |
| |
| name |
| The project name, which must be unique within the owning domain. |
| |
| description |
| The project description. |
| |
| enabled |
| Enables or disables the project. |
| |
| profile |
| Configuration profile - if configuration for multiple openstack accounts required. |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.project_update name=admin enabled=True |
| salt '*' keystone.project_update c965f79c4f864eaaa9c3b41904e67082 name=admin email=admin@domain.com |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if _client_version(kstone) > 2: |
| return tenant_update(tenant_id=project_id, name=name, description=description, |
| enabled=enabled, profile=profile, **connection_args) |
| else: |
| return False |
| |
| |
| def token_get(profile=None, **connection_args): |
| ''' |
| Return the configured tokens (keystone token-get) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.token_get c965f79c4f864eaaa9c3b41904e67082 |
| ''' |
| kstone = auth(profile, **connection_args) |
| token = kstone.service_catalog.get_token() |
| return {'id': token['id'], |
| 'expires': token['expires'], |
| 'user_id': token['user_id'], |
| 'tenant_id': token['tenant_id']} |
| |
| |
| def user_list(profile=None, **connection_args): |
| ''' |
| Return a list of available users (keystone user-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| for user in kstone.users.list(): |
| ret[user.name] = dict((value, getattr(user, value, None)) for value in dir(user) |
| if not value.startswith('_') and |
| isinstance(getattr(user, value, None), (six.string_types, dict, bool))) |
| tenant_id = getattr(user, 'tenantId', None) |
| if tenant_id: |
| ret[user.name]['tenant_id'] = tenant_id |
| return ret |
| |
| |
| def user_get(user_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Return a specific users (keystone user-get) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_get c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.user_get user_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.user_get name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| if name: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| try: |
| user = kstone.users.get(user_id) |
| except keystoneclient.exceptions.NotFound: |
| msg = 'Could not find user \'{0}\''.format(user_id) |
| log.error(msg) |
| return {'Error': msg} |
| |
| ret[user.name] = dict((value, getattr(user, value, None)) for value in dir(user) |
| if not value.startswith('_') and |
| isinstance(getattr(user, value, None), (six.string_types, dict, bool))) |
| |
| tenant_id = getattr(user, 'tenantId', None) |
| if tenant_id: |
| ret[user.name]['tenant_id'] = tenant_id |
| return ret |
| |
| |
| def user_create(name, password, email, tenant_id=None, |
| enabled=True, profile=None, project_id=None, description=None, **connection_args): |
| ''' |
| Create a user (keystone user-create) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_create name=jack password=zero email=jack@halloweentown.org \ |
| tenant_id=a28a7b5a999a455f84b1f5210264375e enabled=True |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if _client_version(kstone) > 2: |
| if tenant_id and not project_id: |
| project_id = tenant_id |
| item = kstone.users.create(name=name, |
| password=password, |
| email=email, |
| project_id=project_id, |
| enabled=enabled, |
| description=description) |
| else: |
| item = kstone.users.create(name=name, |
| password=password, |
| email=email, |
| tenant_id=tenant_id, |
| enabled=enabled) |
| return user_get(item.id, profile=profile, **connection_args) |
| |
| |
| def user_delete(user_id=None, name=None, profile=None, **connection_args): |
| ''' |
| Delete a user (keystone user-delete) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_delete c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.user_delete user_id=c965f79c4f864eaaa9c3b41904e67082 |
| salt '*' keystone.user_delete name=nova |
| ''' |
| kstone = auth(profile, **connection_args) |
| if name: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| kstone.users.delete(user_id) |
| ret = 'User ID {0} deleted'.format(user_id) |
| if name: |
| |
| ret += ' ({0})'.format(name) |
| return ret |
| |
| |
| def user_update(user_id=None, name=None, email=None, enabled=None, options=None, |
| tenant=None, profile=None, project=None, description=None, **connection_args): |
| ''' |
| Update a user's information (keystone user-update) |
| The following fields may be updated: name, email, enabled, tenant, options. |
| Because the name is one of the fields, a valid user id is required. |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_update user_id=c965f79c4f864eaaa9c3b41904e67082 name=newname |
| salt '*' keystone.user_update c965f79c4f864eaaa9c3b41904e67082 name=newname email=newemail@domain.com |
| ''' |
| kstone = auth(profile, **connection_args) |
| if not user_id: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| user = kstone.users.get(user_id) |
| # Keep previous settings if not updating them |
| if not name: |
| name = user.name |
| if not email: |
| email = user.email |
| if enabled is None: |
| enabled = user.enabled |
| if not options: |
| options = {} |
| |
| if _client_version(kstone) > 2: |
| if description is None: |
| description = getattr(user, 'description', None) |
| else: |
| description = str(description) |
| |
| project_id = None |
| if project: |
| for proj in kstone.projects.list(): |
| if proj.name == project: |
| project_id = proj.id |
| break |
| if not project_id: |
| project_id = getattr(user, 'project_id', None) |
| |
| kstone.users.update(user=user_id, name=name, email=email, enabled=enabled, description=description, |
| options=options, project_id=project_id) |
| else: |
| kstone.users.update(user=user_id, name=name, email=email, options=options, enabled=enabled) |
| |
| tenant_id = None |
| if tenant: |
| for tnt in kstone.tenants.list(): |
| if tnt.name == tenant: |
| tenant_id = tnt.id |
| break |
| if tenant_id: |
| kstone.users.update_tenant(user_id, tenant_id) |
| |
| ret = 'Info updated for user ID {0}'.format(user_id) |
| return ret |
| |
| |
| def user_verify_password(user_id=None, name=None, password=None, |
| profile=None, **connection_args): |
| ''' |
| Verify a user's password |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_verify_password name=test password=foobar |
| salt '*' keystone.user_verify_password user_id=c965f79c4f864eaaa9c3b41904e67082 password=foobar |
| ''' |
| kstone = auth(profile, **connection_args) |
| if 'connection_endpoint' in connection_args: |
| auth_url = connection_args.get('connection_endpoint') |
| else: |
| if _client_version(kstone) > 2: |
| auth_url = __salt__['config.option']('keystone.endpoint', |
| 'http://127.0.0.1:35357/v3') |
| else: |
| auth_url = __salt__['config.option']('keystone.endpoint', |
| 'http://127.0.0.1:35357/v2.0') |
| |
| if user_id: |
| for user in kstone.users.list(): |
| if user.id == user_id: |
| name = user.name |
| break |
| if not name: |
| return {'Error': 'Unable to resolve user name'} |
| kwargs = {'username': name, |
| 'password': password, |
| 'auth_url': auth_url} |
| try: |
| if _client_version(kstone) > 2: |
| client3.Client(**kwargs).authenticate() |
| else: |
| client.Client(**kwargs).authenticate() |
| except (keystoneclient.exceptions.Unauthorized, |
| keystoneclient.exceptions.AuthorizationFailure): |
| return False |
| return True |
| |
| |
| def user_password_update(user_id=None, name=None, password=None, |
| profile=None, **connection_args): |
| ''' |
| Update a user's password (keystone user-password-update) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_password_update c965f79c4f864eaaa9c3b41904e67082 password=12345 |
| salt '*' keystone.user_password_update user_id=c965f79c4f864eaaa9c3b41904e67082 password=12345 |
| salt '*' keystone.user_password_update name=nova password=12345 |
| ''' |
| kstone = auth(profile, **connection_args) |
| if name: |
| for user in kstone.users.list(): |
| if user.name == name: |
| user_id = user.id |
| break |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| |
| if _client_version(kstone) > 2: |
| kstone.users.update(user=user_id, password=password) |
| else: |
| kstone.users.update_password(user=user_id, password=password) |
| ret = 'Password updated for user ID {0}'.format(user_id) |
| if name: |
| ret += ' ({0})'.format(name) |
| return ret |
| |
| |
| def user_role_add(user_id=None, user=None, tenant_id=None, |
| tenant=None, role_id=None, role=None, profile=None, |
| project_id=None, project_name=None, **connection_args): |
| ''' |
| Add role for user in tenant (keystone user-role-add) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_role_add \ |
| user_id=298ce377245c4ec9b70e1c639c89e654 \ |
| tenant_id=7167a092ece84bae8cead4bf9d15bb3b \ |
| role_id=ce377245c4ec9b70e1c639c89e8cead4 |
| salt '*' keystone.user_role_add user=admin tenant=admin role=admin |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if project_id and not tenant_id: |
| tenant_id = project_id |
| elif project_name and not tenant: |
| tenant = project_name |
| |
| if user: |
| user_id = user_get(name=user, profile=profile, |
| **connection_args)[user].get('id') |
| else: |
| user = next(six.iterkeys(user_get(user_id, profile=profile, |
| **connection_args)))['name'] |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| |
| if tenant: |
| tenant_id = tenant_get(name=tenant, profile=profile, |
| **connection_args)[tenant].get('id') |
| else: |
| tenant = next(six.iterkeys(tenant_get(tenant_id, profile=profile, |
| **connection_args)))['name'] |
| if not tenant_id: |
| return {'Error': 'Unable to resolve tenant/project id'} |
| |
| if role: |
| role_id = role_get(name=role, profile=profile, |
| **connection_args)[role]['id'] |
| else: |
| role = next(six.iterkeys(role_get(role_id, profile=profile, |
| **connection_args)))['name'] |
| if not role_id: |
| return {'Error': 'Unable to resolve role id'} |
| |
| if _client_version(kstone) > 2: |
| kstone.roles.grant(role_id, user=user_id, project=tenant_id) |
| else: |
| kstone.roles.add_user_role(user_id, role_id, tenant_id) |
| ret_msg = '"{0}" role added for user "{1}" for "{2}" tenant/project' |
| return ret_msg.format(role, user, tenant) |
| |
| |
| def user_role_remove(user_id=None, user=None, tenant_id=None, |
| tenant=None, role_id=None, role=None, |
| profile=None, project_id=None, project_name=None, **connection_args): |
| ''' |
| Remove role for user in tenant (keystone user-role-remove) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_role_remove \ |
| user_id=298ce377245c4ec9b70e1c639c89e654 \ |
| tenant_id=7167a092ece84bae8cead4bf9d15bb3b \ |
| role_id=ce377245c4ec9b70e1c639c89e8cead4 |
| salt '*' keystone.user_role_remove user=admin tenant=admin role=admin |
| ''' |
| kstone = auth(profile, **connection_args) |
| |
| if project_id and not tenant_id: |
| tenant_id = project_id |
| elif project_name and not tenant: |
| tenant = project_name |
| |
| if user: |
| user_id = user_get(name=user, profile=profile, |
| **connection_args)[user].get('id') |
| else: |
| user = next(six.iterkeys(user_get(user_id, profile=profile, |
| **connection_args)))['name'] |
| if not user_id: |
| return {'Error': 'Unable to resolve user id'} |
| |
| if tenant: |
| tenant_id = tenant_get(name=tenant, profile=profile, |
| **connection_args)[tenant].get('id') |
| else: |
| tenant = next(six.iterkeys(tenant_get(tenant_id, profile=profile, |
| **connection_args)))['name'] |
| if not tenant_id: |
| return {'Error': 'Unable to resolve tenant/project id'} |
| |
| if role: |
| role_id = role_get(name=role, profile=profile, |
| **connection_args)[role]['id'] |
| else: |
| role = next(six.iterkeys(role_get(role_id)))['name'] |
| if not role_id: |
| return {'Error': 'Unable to resolve role id'} |
| |
| if _client_version(kstone) > 2: |
| kstone.roles.revoke(role_id, user=user_id, project=tenant_id) |
| else: |
| kstone.roles.remove_user_role(user_id, role_id, tenant_id) |
| ret_msg = '"{0}" role removed for user "{1}" under "{2}" tenant' |
| return ret_msg.format(role, user, tenant) |
| |
| |
| def user_role_list(user_id=None, tenant_id=None, user_name=None, |
| tenant_name=None, profile=None, project_id=None, project_name=None, **connection_args): |
| ''' |
| Return a list of available user_roles (keystone user-roles-list) |
| |
| CLI Examples: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.user_role_list \ |
| user_id=298ce377245c4ec9b70e1c639c89e654 \ |
| tenant_id=7167a092ece84bae8cead4bf9d15bb3b |
| salt '*' keystone.user_role_list user_name=admin tenant_name=admin |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = {} |
| |
| if project_id and not tenant_id: |
| tenant_id = project_id |
| elif project_name and not tenant_name: |
| tenant_name = project_name |
| |
| if user_name: |
| for user in kstone.users.list(): |
| if user.name == user_name: |
| user_id = user.id |
| break |
| if tenant_name: |
| for tenant in _project_mgr(kstone).list(): |
| if tenant.name == tenant_name: |
| tenant_id = tenant.id |
| break |
| if not user_id or not tenant_id: |
| return {'Error': 'Unable to resolve user or tenant/project id'} |
| |
| if _client_version(kstone) > 2: |
| for role in kstone.roles.list(user=user_id, project=tenant_id): |
| ret[role.name] = dict((value, getattr(role, value)) for value in dir(role) |
| if not value.startswith('_') and |
| isinstance(getattr(role, value), (six.string_types, dict, bool))) |
| else: |
| for role in kstone.roles.roles_for_user(user=user_id, tenant=tenant_id): |
| ret[role.name] = {'id': role.id, |
| 'name': role.name, |
| 'user_id': user_id, |
| 'tenant_id': tenant_id} |
| return ret |
| |
| |
| def _item_list(profile=None, **connection_args): |
| ''' |
| Template for writing list functions |
| Return a list of available items (keystone items-list) |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' keystone.item_list |
| ''' |
| kstone = auth(profile, **connection_args) |
| ret = [] |
| for item in kstone.items.list(): |
| ret.append(item.__dict__) |
| # ret[item.name] = { |
| # 'id': item.id, |
| # 'name': item.name, |
| # } |
| return ret |
| |
| # The following is a list of functions that need to be incorporated in the |
| # keystone module. This list should be updated as functions are added. |
| # |
| # endpoint-create Create a new endpoint associated with a service |
| # endpoint-delete Delete a service endpoint |
| # discover Discover Keystone servers and show authentication |
| # protocols and |
| # bootstrap Grants a new role to a new user on a new tenant, after |
| # creating each. |