1 # Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from keystoneclient.client import Client
18 from keystoneauth1.identity import v3, v2
19 from keystoneauth1 import session
22 from snaps.domain.project import Project
23 from snaps.domain.role import Role
24 from snaps.domain.user import User
26 logger = logging.getLogger('keystone_utils')
31 def get_session_auth(os_creds):
33 Return the session auth for keystone session
34 :param os_creds: the OpenStack credentials (OSCreds) object
37 if os_creds.identity_api_version == 3:
38 auth = v3.Password(auth_url=os_creds.auth_url,
39 username=os_creds.username,
40 password=os_creds.password,
41 project_name=os_creds.project_name,
42 user_domain_id=os_creds.user_domain_id,
43 project_domain_id=os_creds.project_domain_id)
45 auth = v2.Password(auth_url=os_creds.auth_url,
46 username=os_creds.username,
47 password=os_creds.password,
48 tenant_name=os_creds.project_name)
52 def keystone_session(os_creds):
54 Creates a keystone session used for authenticating OpenStack clients
55 :param os_creds: The connection credentials to the OpenStack API
56 :return: the client object
58 logger.debug('Retrieving Keystone Session')
60 auth = get_session_auth(os_creds)
63 if os_creds.proxy_settings:
64 req_session = requests.Session()
65 req_session.proxies = {
67 os_creds.proxy_settings.host + ':' +
68 os_creds.proxy_settings.port}
69 return session.Session(auth=auth, session=req_session,
70 verify=os_creds.cacert)
73 def keystone_client(os_creds):
75 Returns the keystone client
76 :param os_creds: the OpenStack credentials (OSCreds) object
80 version=os_creds.identity_api_version,
81 session=keystone_session(os_creds), interface=os_creds.interface)
84 def get_endpoint(os_creds, service_type, interface='public'):
86 Returns the endpoint of specific service
87 :param os_creds: the OpenStack credentials (OSCreds) object
88 :param service_type: the type of specific service
89 :param interface: the type of interface
90 :return: the endpoint url
92 auth = get_session_auth(os_creds)
93 key_session = keystone_session(os_creds)
94 return key_session.get_endpoint(
95 auth=auth, service_type=service_type, interface=interface)
98 def get_project(keystone=None, os_creds=None, project_name=None):
100 Returns the first project object or None if not found
101 :param keystone: the Keystone client
102 :param os_creds: the OpenStack credentials used to obtain the Keystone
103 client if the keystone parameter is None
104 :param project_name: the name to query
105 :return: the ID or None
112 keystone = keystone_client(os_creds)
114 raise KeystoneException(
115 'Cannot lookup project without the proper credentials')
117 if keystone.version == V2_VERSION:
118 projects = keystone.tenants.list()
120 projects = keystone.projects.list(**{'name': project_name})
122 for project in projects:
123 if project.name == project_name:
124 return Project(name=project.name, project_id=project.id)
129 def create_project(keystone, project_settings):
132 :param keystone: the Keystone client
133 :param project_settings: the project configuration
134 :return: SNAPS-OO Project domain object
136 if keystone.version == V2_VERSION:
137 return keystone.tenants.create(
138 project_settings.name, project_settings.description,
139 project_settings.enabled)
141 return keystone.projects.create(
142 project_settings.name, project_settings.domain,
143 description=project_settings.description,
144 enabled=project_settings.enabled)
147 def delete_project(keystone, project):
150 :param keystone: the Keystone clien
151 :param project: the SNAPS-OO Project domain object
153 if keystone.version == V2_VERSION:
154 keystone.tenants.delete(project.id)
156 keystone.projects.delete(project.id)
159 def __get_os_user(keystone, user):
161 Returns the OpenStack user object
162 :param keystone: the Keystone client object
163 :param user: the SNAPS-OO User domain object
166 return keystone.users.get(user.id)
169 def get_user(keystone, username, project_name=None):
171 Returns a user for a given name and optionally project
172 :param keystone: the keystone client
173 :param username: the username to lookup
174 :param project_name: the associated project (optional)
175 :return: a SNAPS-OO User domain object or None
177 project = get_project(keystone=keystone, project_name=project_name)
180 users = keystone.users.list(tenant_id=project.id)
182 users = keystone.users.list()
185 if user.name == username:
186 return User(name=user.name, user_id=user.id)
191 def create_user(keystone, user_settings):
194 :param keystone: the Keystone client
195 :param user_settings: the user configuration
196 :return: a SNAPS-OO User domain object
199 if user_settings.project_name:
200 project = get_project(keystone=keystone,
201 project_name=user_settings.project_name)
203 if keystone.version == V2_VERSION:
206 project_id = project.id
207 os_user = keystone.users.create(
208 name=user_settings.name, password=user_settings.password,
209 email=user_settings.email, tenant_id=project_id,
210 enabled=user_settings.enabled)
212 os_user = keystone.users.create(
213 name=user_settings.name, password=user_settings.password,
214 email=user_settings.email, project=project,
215 domain=user_settings.domain_name, enabled=user_settings.enabled)
217 for role_name, role_project in user_settings.roles.items():
218 os_role = _get_os_role_by_name(keystone, role_name)
219 os_project = get_project(keystone=keystone, project_name=role_project)
221 if os_role and os_project:
222 existing_roles = _get_os_roles_by_user(keystone, os_user,
225 for role in existing_roles:
226 if role.id == os_role.id:
230 grant_user_role_to_project(
231 keystone=keystone, user=os_user, role=os_role,
235 return User(name=os_user.name, user_id=os_user.id)
238 def delete_user(keystone, user):
241 :param keystone: the Keystone client
242 :param user: the SNAPS-OO User domain object
244 keystone.users.delete(user.id)
247 def _get_os_role_by_name(keystone, name):
249 Returns an OpenStack role object of a given name or None if not exists
250 :param keystone: the keystone client
251 :param name: the role name
252 :return: the SNAPS-OO Role domain object
254 roles = keystone.roles.list()
256 if role.name == name:
257 return Role(name=role.name, role_id=role.id)
260 def _get_os_roles_by_user(keystone, user, project):
262 Returns a list of OpenStack role object associated with a user
263 :param keystone: the keystone client
264 :param user: the OpenStack user object
265 :param project: the OpenStack project object (only required for v2)
266 :return: a list of SNAPS-OO Role domain objects
268 if keystone.version == V2_VERSION:
269 os_user = __get_os_user(keystone, user)
270 roles = keystone.roles.roles_for_user(os_user, project)
272 roles = keystone.roles.list(user=user, project=project)
276 out.append(Role(name=role.name, role_id=role.id))
280 def __get_os_role_by_id(keystone, role_id):
282 Returns an OpenStack role object of a given name or None if not exists
283 :param keystone: the keystone client
284 :param role_id: the role ID
285 :return: a SNAPS-OO Role domain object
287 role = keystone.roles.get(role_id)
288 return Role(name=role.name, role_id=role.id)
291 def create_role(keystone, name):
293 Creates an OpenStack role
294 :param keystone: the keystone client
295 :param name: the role name
296 :return: a SNAPS-OO Role domain object
298 role = keystone.roles.create(name)
299 return Role(name=role.name, role_id=role.id)
302 def delete_role(keystone, role):
304 Deletes an OpenStack role
305 :param keystone: the keystone client
306 :param role: the SNAPS-OO Role domain object to delete
309 keystone.roles.delete(role.id)
312 def grant_user_role_to_project(keystone, role, user, project):
314 Grants user and role to a project
315 :param keystone: the Keystone client
316 :param role: the SNAPS-OO Role domain object used to join a project/user
317 :param user: the user to add to the project (SNAPS-OO User Domain object
318 :param project: the project to which to add a user
322 os_role = __get_os_role_by_id(keystone, role.id)
323 if keystone.version == V2_VERSION:
324 keystone.roles.add_user_role(user, os_role, tenant=project)
326 keystone.roles.grant(os_role, user=user, project=project)
329 class KeystoneException(Exception):
331 Exception when calls to the Keystone client cannot be served properly