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.user import User
25 logger = logging.getLogger('keystone_utils')
30 def get_session_auth(os_creds):
32 Return the session auth for keystone session
33 :param os_creds: the OpenStack credentials (OSCreds) object
36 if os_creds.identity_api_version == 3:
37 auth = v3.Password(auth_url=os_creds.auth_url,
38 username=os_creds.username,
39 password=os_creds.password,
40 project_name=os_creds.project_name,
41 user_domain_id=os_creds.user_domain_id,
42 project_domain_id=os_creds.project_domain_id)
44 auth = v2.Password(auth_url=os_creds.auth_url,
45 username=os_creds.username,
46 password=os_creds.password,
47 tenant_name=os_creds.project_name)
51 def keystone_session(os_creds):
53 Creates a keystone session used for authenticating OpenStack clients
54 :param os_creds: The connection credentials to the OpenStack API
55 :return: the client object
57 logger.debug('Retrieving Keystone Session')
59 auth = get_session_auth(os_creds)
62 if os_creds.proxy_settings:
63 req_session = requests.Session()
64 req_session.proxies = {
66 os_creds.proxy_settings.host + ':' +
67 os_creds.proxy_settings.port}
68 return session.Session(auth=auth, session=req_session,
69 verify=os_creds.cacert)
72 def keystone_client(os_creds):
74 Returns the keystone client
75 :param os_creds: the OpenStack credentials (OSCreds) object
79 version=os_creds.identity_api_version,
80 session=keystone_session(os_creds), interface=os_creds.interface)
83 def get_endpoint(os_creds, service_type, interface='public'):
85 Returns the endpoint of specific service
86 :param os_creds: the OpenStack credentials (OSCreds) object
87 :param service_type: the type of specific service
88 :param interface: the type of interface
89 :return: the endpoint url
91 auth = get_session_auth(os_creds)
92 key_session = keystone_session(os_creds)
93 return key_session.get_endpoint(
94 auth=auth, service_type=service_type, interface=interface)
97 def get_project(keystone=None, os_creds=None, project_name=None):
99 Returns the first project object or None if not found
100 :param keystone: the Keystone client
101 :param os_creds: the OpenStack credentials used to obtain the Keystone
102 client if the keystone parameter is None
103 :param project_name: the name to query
104 :return: the ID or None
111 keystone = keystone_client(os_creds)
113 raise Exception('Cannot lookup project without the proper '
116 if keystone.version == V2_VERSION:
117 projects = keystone.tenants.list()
119 projects = keystone.projects.list(**{'name': project_name})
121 for project in projects:
122 if project.name == project_name:
123 return Project(name=project.name, project_id=project.id)
128 def create_project(keystone, project_settings):
131 :param keystone: the Keystone client
132 :param project_settings: the project configuration
133 :return: SNAPS-OO Project domain object
135 if keystone.version == V2_VERSION:
136 return keystone.tenants.create(
137 project_settings.name, project_settings.description,
138 project_settings.enabled)
140 return keystone.projects.create(
141 project_settings.name, project_settings.domain,
142 description=project_settings.description,
143 enabled=project_settings.enabled)
146 def delete_project(keystone, project):
149 :param keystone: the Keystone clien
150 :param project: the SNAPS-OO Project domain object
152 if keystone.version == V2_VERSION:
153 keystone.tenants.delete(project.id)
155 keystone.projects.delete(project.id)
158 def get_os_user(keystone, user):
160 Returns the OpenStack user object
161 :param keystone: the Keystone client object
162 :param user: the SNAPS-OO User domain object
165 return keystone.users.get(user.id)
168 def get_user(keystone, username, project_name=None):
170 Returns a user for a given name and optionally project
171 :param keystone: the keystone client
172 :param username: the username to lookup
173 :param project_name: the associated project (optional)
174 :return: a SNAPS-OO User domain object or None
176 project = get_project(keystone=keystone, project_name=project_name)
179 users = keystone.users.list(tenant_id=project.id)
181 users = keystone.users.list()
184 if user.name == username:
185 return User(name=user.name, user_id=user.id)
190 def create_user(keystone, user_settings):
193 :param keystone: the Keystone client
194 :param user_settings: the user configuration
195 :return: a SNAPS-OO User domain object
198 if user_settings.project_name:
199 project = get_project(keystone=keystone,
200 project_name=user_settings.project_name)
202 if keystone.version == V2_VERSION:
205 project_id = project.id
206 os_user = keystone.users.create(
207 name=user_settings.name, password=user_settings.password,
208 email=user_settings.email, tenant_id=project_id,
209 enabled=user_settings.enabled)
211 os_user = keystone.users.create(
212 name=user_settings.name, password=user_settings.password,
213 email=user_settings.email, project=project,
214 domain=user_settings.domain_name, enabled=user_settings.enabled)
216 for role_name, role_project in user_settings.roles.items():
217 os_role = get_os_role_by_name(keystone, role_name)
218 os_project = get_project(keystone=keystone, project_name=role_project)
220 if os_role and os_project:
221 existing_roles = get_os_roles_by_user(keystone, os_user,
224 for role in existing_roles:
225 if role.id == os_role.id:
229 grant_user_role_to_project(
230 keystone=keystone, user=os_user, role=os_role,
234 return User(name=os_user.name, user_id=os_user.id)
237 def delete_user(keystone, user):
240 :param keystone: the Keystone client
241 :param user: the SNAPS-OO User domain object
243 keystone.users.delete(user.id)
246 def get_os_role_by_name(keystone, name):
248 Returns an OpenStack role object of a given name or None if not exists
249 :param keystone: the keystone client
250 :param name: the role name
251 :return: the OpenStack role object
253 roles = keystone.roles.list()
255 if role.name == name:
259 def get_os_roles_by_user(keystone, user, project):
261 Returns a list of OpenStack role object associated with a user
262 :param keystone: the keystone client
263 :param user: the OpenStack user object
264 :param project: the OpenStack project object (only required for v2)
265 :return: a list of OpenStack role objects
267 if keystone.version == V2_VERSION:
268 os_user = get_os_user(keystone, user)
269 roles = keystone.roles.roles_for_user(os_user, project)
272 return keystone.roles.list(user=user, project=project)
275 def get_os_role_by_id(keystone, role_id):
277 Returns an OpenStack role object of a given name or None if not exists
278 :param keystone: the keystone client
279 :param role_id: the role ID
280 :return: the OpenStack role object
282 return keystone.roles.get(role_id)
285 def create_role(keystone, name):
287 Creates an OpenStack role
288 :param keystone: the keystone client
289 :param name: the role name
292 return keystone.roles.create(name)
295 def delete_role(keystone, role):
297 Deletes an OpenStack role
298 :param keystone: the keystone client
299 :param role: the role to delete
302 keystone.roles.delete(role)
305 def grant_user_role_to_project(keystone, role, user, project):
307 Grants user and role to a project
308 :param keystone: the Keystone client
309 :param role: the role used to join a project/user
310 :param user: the user to add to the project (SNAPS-OO User Domain object
311 :param project: the project to which to add a user
314 if keystone.version == V2_VERSION:
315 keystone.roles.add_user_role(user, role, tenant=project)
317 keystone.roles.grant(role, user=user, project=project)