Crteated domain class for projects.
[snaps.git] / snaps / openstack / utils / keystone_utils.py
1 # Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
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:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15 import logging
16
17 from keystoneclient.client import Client
18 from keystoneauth1.identity import v3, v2
19 from keystoneauth1 import session
20 import requests
21
22 from snaps.domain.project import Project
23 from snaps.domain.user import User
24
25 logger = logging.getLogger('keystone_utils')
26
27 V2_VERSION = 'v2.0'
28
29
30 def get_session_auth(os_creds):
31     """
32     Return the session auth for keystone session
33     :param os_creds: the OpenStack credentials (OSCreds) object
34     :return: the auth
35     """
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)
43     else:
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)
48     return auth
49
50
51 def keystone_session(os_creds):
52     """
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
56     """
57     logger.debug('Retrieving Keystone Session')
58
59     auth = get_session_auth(os_creds)
60
61     req_session = None
62     if os_creds.proxy_settings:
63         req_session = requests.Session()
64         req_session.proxies = {
65             'http':
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)
70
71
72 def keystone_client(os_creds):
73     """
74     Returns the keystone client
75     :param os_creds: the OpenStack credentials (OSCreds) object
76     :return: the client
77     """
78     return Client(
79         version=os_creds.identity_api_version,
80         session=keystone_session(os_creds), interface=os_creds.interface)
81
82
83 def get_endpoint(os_creds, service_type, interface='public'):
84     """
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
90     """
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)
95
96
97 def get_project(keystone=None, os_creds=None, project_name=None):
98     """
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
105     """
106     if not project_name:
107         return None
108
109     if not keystone:
110         if os_creds:
111             keystone = keystone_client(os_creds)
112         else:
113             raise Exception('Cannot lookup project without the proper '
114                             'credentials')
115
116     if keystone.version == V2_VERSION:
117         projects = keystone.tenants.list()
118     else:
119         projects = keystone.projects.list(**{'name': project_name})
120
121     for project in projects:
122         if project.name == project_name:
123             return Project(name=project.name, project_id=project.id)
124
125     return None
126
127
128 def create_project(keystone, project_settings):
129     """
130     Creates a project
131     :param keystone: the Keystone client
132     :param project_settings: the project configuration
133     :return: SNAPS-OO Project domain object
134     """
135     if keystone.version == V2_VERSION:
136         return keystone.tenants.create(
137             project_settings.name, project_settings.description,
138             project_settings.enabled)
139
140     return keystone.projects.create(
141         project_settings.name, project_settings.domain,
142         description=project_settings.description,
143         enabled=project_settings.enabled)
144
145
146 def delete_project(keystone, project):
147     """
148     Deletes a project
149     :param keystone: the Keystone clien
150     :param project: the SNAPS-OO Project domain object
151     """
152     if keystone.version == V2_VERSION:
153         keystone.tenants.delete(project.id)
154     else:
155         keystone.projects.delete(project.id)
156
157
158 def get_os_user(keystone, user):
159     """
160     Returns the OpenStack user object
161     :param keystone: the Keystone client object
162     :param user: the SNAPS-OO User domain object
163     :return:
164     """
165     return keystone.users.get(user.id)
166
167
168 def get_user(keystone, username, project_name=None):
169     """
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
175     """
176     project = get_project(keystone=keystone, project_name=project_name)
177
178     if project:
179         users = keystone.users.list(tenant_id=project.id)
180     else:
181         users = keystone.users.list()
182
183     for user in users:
184         if user.name == username:
185             return User(name=user.name, user_id=user.id)
186
187     return None
188
189
190 def create_user(keystone, user_settings):
191     """
192     Creates a user
193     :param keystone: the Keystone client
194     :param user_settings: the user configuration
195     :return: a SNAPS-OO User domain object
196     """
197     project = None
198     if user_settings.project_name:
199         project = get_project(keystone=keystone,
200                               project_name=user_settings.project_name)
201
202     if keystone.version == V2_VERSION:
203         project_id = None
204         if project:
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)
210     else:
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)
215
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)
219
220         if os_role and os_project:
221             existing_roles = get_os_roles_by_user(keystone, os_user,
222                                                   os_project)
223             found = False
224             for role in existing_roles:
225                 if role.id == os_role.id:
226                     found = True
227
228             if not found:
229                 grant_user_role_to_project(
230                     keystone=keystone, user=os_user, role=os_role,
231                     project=os_project)
232
233     if os_user:
234         return User(name=os_user.name, user_id=os_user.id)
235
236
237 def delete_user(keystone, user):
238     """
239     Deletes a user
240     :param keystone: the Keystone client
241     :param user: the SNAPS-OO User domain object
242     """
243     keystone.users.delete(user.id)
244
245
246 def get_os_role_by_name(keystone, name):
247     """
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
252     """
253     roles = keystone.roles.list()
254     for role in roles:
255         if role.name == name:
256             return role
257
258
259 def get_os_roles_by_user(keystone, user, project):
260     """
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
266     """
267     if keystone.version == V2_VERSION:
268         os_user = get_os_user(keystone, user)
269         roles = keystone.roles.roles_for_user(os_user, project)
270         return roles
271     else:
272         return keystone.roles.list(user=user, project=project)
273
274
275 def get_os_role_by_id(keystone, role_id):
276     """
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
281     """
282     return keystone.roles.get(role_id)
283
284
285 def create_role(keystone, name):
286     """
287     Creates an OpenStack role
288     :param keystone: the keystone client
289     :param name: the role name
290     :return:
291     """
292     return keystone.roles.create(name)
293
294
295 def delete_role(keystone, role):
296     """
297     Deletes an OpenStack role
298     :param keystone: the keystone client
299     :param role: the role to delete
300     :return:
301     """
302     keystone.roles.delete(role)
303
304
305 def grant_user_role_to_project(keystone, role, user, project):
306     """
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
312     :return:
313     """
314     if keystone.version == V2_VERSION:
315         keystone.roles.add_user_role(user, role, tenant=project)
316     else:
317         keystone.roles.grant(role, user=user, project=project)