Code Coverage

Cobertura Coverage Report > osmclient.cli_commands >

rbac.py

Trend

File Coverage summary

NameClassesLinesConditionals
rbac.py
100%
1/1
41%
90/221
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
rbac.py
41%
90/221
N/A

Source

osmclient/cli_commands/rbac.py
1 # Copyright ETSI Contributors and Others.
2 # All Rights Reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    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, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15
16 1 import click
17 1 from osmclient.common.exceptions import ClientException
18 1 from osmclient.cli_commands import utils
19 1 from prettytable import PrettyTable
20 1 import json
21 1 import logging
22 1 import time
23
24 1 logger = logging.getLogger("osmclient")
25
26
27 ##############################
28 # Role Management Operations #
29 ##############################
30
31
32 1 @click.command(name="role-create", short_help="creates a new role")
33 1 @click.argument("name")
34 1 @click.option("--permissions", default=None, help="role permissions using a dictionary")
35 1 @click.pass_context
36 1 def role_create(ctx, name, permissions):
37     """
38     Creates a new role.
39
40     \b
41     NAME: Name or ID of the role.
42     DEFINITION: Definition of grant/denial of access to resources.
43     """
44 0     logger.debug("")
45 0     utils.check_client_version(ctx.obj, ctx.command.name)
46 0     ctx.obj.role.create(name, permissions)
47
48
49 1 @click.command(name="role-update", short_help="updates a role")
50 1 @click.argument("name")
51 1 @click.option("--set-name", default=None, help="change name of rle")
52 1 @click.option(
53     "--add",
54     default=None,
55     help="yaml format dictionary with permission: True/False to access grant/denial",
56 )
57 1 @click.option("--remove", default=None, help="yaml format list to remove a permission")
58 1 @click.pass_context
59 1 def role_update(ctx, name, set_name, add, remove):
60     """
61     Updates a role.
62
63     \b
64     NAME: Name or ID of the role.
65     DEFINITION: Definition overwrites the old definition.
66     ADD: Grant/denial of access to resource to add.
67     REMOVE: Grant/denial of access to resource to remove.
68     """
69 0     logger.debug("")
70 0     utils.check_client_version(ctx.obj, ctx.command.name)
71 0     ctx.obj.role.update(name, set_name, None, add, remove)
72
73
74 1 @click.command(name="role-delete", short_help="deletes a role")
75 1 @click.argument("name")
76 1 @click.pass_context
77 1 def role_delete(ctx, name):
78     """
79     Deletes a role.
80
81     \b
82     NAME: Name or ID of the role.
83     """
84 0     logger.debug("")
85 0     utils.check_client_version(ctx.obj, ctx.command.name)
86 0     ctx.obj.role.delete(name)
87
88
89 1 @click.command(name="role-list", short_help="list all roles")
90 1 @click.option(
91     "--filter",
92     default=None,
93     multiple=True,
94     help="restricts the list to the projects matching the filter",
95 )
96 1 @click.pass_context
97 1 def role_list(ctx, filter):
98     """
99     List all roles.
100     """
101 0     logger.debug("")
102 0     utils.check_client_version(ctx.obj, ctx.command.name)
103 0     if filter:
104 0         filter = "&".join(filter)
105 0     resp = ctx.obj.role.list(filter)
106 0     table = PrettyTable(["name", "id"])
107 0     for role in resp:
108 0         table.add_row([role["name"], role["_id"]])
109 0     table.align = "l"
110 0     print(table)
111
112
113 1 @click.command(name="role-show", short_help="show specific role")
114 1 @click.argument("name")
115 1 @click.pass_context
116 1 def role_show(ctx, name):
117     """
118     Shows the details of a role.
119
120     \b
121     NAME: Name or ID of the role.
122     """
123 0     logger.debug("")
124 0     utils.check_client_version(ctx.obj, ctx.command.name)
125 0     resp = ctx.obj.role.get(name)
126
127 0     table = PrettyTable(["key", "attribute"])
128 0     for k, v in resp.items():
129 0         table.add_row([k, json.dumps(v, indent=2)])
130 0     table.align = "l"
131 0     print(table)
132
133
134 ####################
135 # Project mgmt operations
136 ####################
137
138
139 1 @click.command(name="project-create", short_help="creates a new project")
140 1 @click.argument("name")
141 # @click.option('--description',
142 #              default='no description',
143 #              help='human readable description')
144 1 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
145 1 @click.option(
146     "--quotas",
147     "quotas",
148     multiple=True,
149     default=None,
150     help="provide quotas. Can be used several times: 'quota1=number[,quota2=number,...]'. Quotas can be one "
151     "of vnfds, nsds, nsts, pdus, nsrs, nsis, vim_accounts, wim_accounts, sdns, k8sclusters, k8srepos",
152 )
153 1 @click.pass_context
154 1 def project_create(ctx, name, domain_name, quotas):
155     """Creates a new project
156
157     NAME: name of the project
158     DOMAIN_NAME: optional domain name for the project when keystone authentication is used
159     QUOTAS: set quotas for the project
160     """
161 0     logger.debug("")
162 0     project = {"name": name}
163 0     if domain_name:
164 0         project["domain_name"] = domain_name
165 0     quotas_dict = _process_project_quotas(quotas)
166 0     if quotas_dict:
167 0         project["quotas"] = quotas_dict
168
169 0     utils.check_client_version(ctx.obj, ctx.command.name)
170 0     ctx.obj.project.create(name, project)
171
172
173 1 def _process_project_quotas(quota_list):
174 0     quotas_dict = {}
175 0     if not quota_list:
176 0         return quotas_dict
177 0     try:
178 0         for quota in quota_list:
179 0             for single_quota in quota.split(","):
180 0                 k, v = single_quota.split("=")
181 0                 quotas_dict[k] = None if v in ("None", "null", "") else int(v)
182 0     except (ValueError, TypeError):
183 0         raise ClientException(
184             "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
185         )
186 0     return quotas_dict
187
188
189 1 @click.command(name="project-delete", short_help="deletes a project")
190 1 @click.argument("name")
191 1 @click.pass_context
192 1 def project_delete(ctx, name):
193     """deletes a project
194
195     NAME: name or ID of the project to be deleted
196     """
197 0     logger.debug("")
198 0     utils.check_client_version(ctx.obj, ctx.command.name)
199 0     ctx.obj.project.delete(name)
200
201
202 1 @click.command(name="project-list", short_help="list all projects")
203 1 @click.option(
204     "--filter",
205     default=None,
206     multiple=True,
207     help="restricts the list to the projects matching the filter",
208 )
209 1 @click.pass_context
210 1 def project_list(ctx, filter):
211     """list all projects"""
212 0     logger.debug("")
213 0     utils.check_client_version(ctx.obj, ctx.command.name)
214 0     if filter:
215 0         filter = "&".join(filter)
216 0     resp = ctx.obj.project.list(filter)
217 0     table = PrettyTable(["name", "id"])
218 0     for proj in resp:
219 0         table.add_row([proj["name"], proj["_id"]])
220 0     table.align = "l"
221 0     print(table)
222
223
224 1 @click.command(name="project-show", short_help="shows the details of a project")
225 1 @click.argument("name")
226 1 @click.pass_context
227 1 def project_show(ctx, name):
228     """shows the details of a project
229
230     NAME: name or ID of the project
231     """
232 0     logger.debug("")
233 0     utils.check_client_version(ctx.obj, ctx.command.name)
234 0     resp = ctx.obj.project.get(name)
235
236 0     table = PrettyTable(["key", "attribute"])
237 0     for k, v in resp.items():
238 0         table.add_row([k, json.dumps(v, indent=2)])
239 0     table.align = "l"
240 0     print(table)
241
242
243 1 @click.command(
244     name="project-update", short_help="updates a project (only the name can be updated)"
245 )
246 1 @click.argument("project")
247 1 @click.option("--name", default=None, help="new name for the project")
248 1 @click.option(
249     "--quotas",
250     "quotas",
251     multiple=True,
252     default=None,
253     help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
254     "(use empty to reset quota to default",
255 )
256 1 @click.pass_context
257 1 def project_update(ctx, project, name, quotas):
258     """
259     Update a project name
260
261     :param ctx:
262     :param project: id or name of the project to modify
263     :param name:  new name for the project
264     :param quotas:  change quotas of the project
265     :return:
266     """
267 0     logger.debug("")
268 0     project_changes = {}
269 0     if name:
270 0         project_changes["name"] = name
271 0     quotas_dict = _process_project_quotas(quotas)
272 0     if quotas_dict:
273 0         project_changes["quotas"] = quotas_dict
274
275 0     utils.check_client_version(ctx.obj, ctx.command.name)
276 0     ctx.obj.project.update(project, project_changes)
277
278
279 ####################
280 # User mgmt operations
281 ####################
282
283
284 1 @click.command(name="user-create", short_help="creates a new user")
285 1 @click.argument("username")
286 1 @click.option(
287     "--password",
288     prompt=True,
289     hide_input=True,
290     confirmation_prompt=True,
291     help="user password",
292 )
293 1 @click.option(
294     "--projects",
295     # prompt="Comma separate list of projects",
296     multiple=True,
297     callback=lambda ctx, param, value: (
298         "".join(value).split(",") if all(len(x) == 1 for x in value) else value
299     ),
300     help="list of project ids that the user belongs to",
301 )
302 1 @click.option(
303     "--project-role-mappings",
304     "project_role_mappings",
305     default=None,
306     multiple=True,
307     help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
308 )
309 1 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
310 1 @click.pass_context
311 1 def user_create(ctx, username, password, projects, project_role_mappings, domain_name):
312     """Creates a new user
313
314     \b
315     USERNAME: name of the user
316     PASSWORD: password of the user
317     PROJECTS: projects assigned to user (internal only)
318     PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
319     DOMAIN_NAME: optional domain name for the user when keystone authentication is used
320     """
321 0     logger.debug("")
322 0     user = {}
323 0     user["username"] = username
324 0     user["password"] = password
325 0     user["projects"] = projects
326 0     user["project_role_mappings"] = project_role_mappings
327 0     if domain_name:
328 0         user["domain_name"] = domain_name
329
330 0     utils.check_client_version(ctx.obj, ctx.command.name)
331 0     ctx.obj.user.create(username, user)
332
333
334 1 @click.command(name="user-update", short_help="updates user information")
335 1 @click.argument("username")
336 1 @click.option("--set-username", "set_username", default=None, help="change username")
337 1 @click.option(
338     "--set-project",
339     "set_project",
340     default=None,
341     multiple=True,
342     help="create/replace the roles for this project: 'project,role1[,role2,...]'",
343 )
344 1 @click.option(
345     "--remove-project",
346     "remove_project",
347     default=None,
348     multiple=True,
349     help="removes project from user: 'project'",
350 )
351 1 @click.option(
352     "--add-project-role",
353     "add_project_role",
354     default=None,
355     multiple=True,
356     help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
357 )
358 1 @click.option(
359     "--remove-project-role",
360     "remove_project_role",
361     default=None,
362     multiple=True,
363     help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
364 )
365 1 @click.option("--current-password", "current_password", help="user's current password")
366 1 @click.option(
367     "--new-password",
368     "new_password",
369     # prompt=True,
370     # hide_input=True,
371     # confirmation_prompt=True,
372     help="new user password",
373 )
374 1 @click.option(
375     "--unlock",
376     is_flag=True,
377     help="unlock user",
378 )
379 1 @click.option(
380     "--renew",
381     is_flag=True,
382     help="renew user",
383 )
384 1 @click.pass_context
385 1 def user_update(
386     ctx,
387     username,
388     set_username,
389     set_project,
390     remove_project,
391     add_project_role,
392     remove_project_role,
393     current_password,
394     new_password,
395     unlock,
396     renew,
397 ):
398     """Update a user information
399
400     \b
401     USERNAME: name of the user
402     SET_USERNAME: new username
403     SET_PROJECT: creating mappings for project/role(s)
404     REMOVE_PROJECT: deleting mappings for project/role(s)
405     ADD_PROJECT_ROLE: adding mappings for project/role(s)
406     REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
407     CURRENT_PASSWORD: user's current password to change
408     NEW_PASSWORD: user's new password to be updated
409     UNLOCK: unlock user
410     RENEW: renew user
411     """
412 0     logger.debug("")
413 0     user = {}
414 0     user["username"] = set_username
415 0     user["set-project"] = set_project
416 0     user["remove-project"] = remove_project
417 0     user["add-project-role"] = add_project_role
418 0     user["remove-project-role"] = remove_project_role
419 0     user["current_password"] = current_password
420 0     user["new_password"] = new_password
421 0     user["unlock"] = unlock
422 0     user["renew"] = renew
423
424 0     utils.check_client_version(ctx.obj, ctx.command.name)
425 0     if not user.get("current_password"):
426         # In case the password is valid but the end user wants to update it
427 0         ctx.obj.user.update(username, user)
428     else:
429         # In case the password has expired (also applies in first login)
430 0         ctx.obj.user.update(username, user, pwd_change=True)
431
432
433 1 @click.command(name="user-delete", short_help="deletes a user")
434 1 @click.argument("name")
435 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
436 1 @click.pass_context
437 1 def user_delete(ctx, name):
438     """deletes a user
439
440     \b
441     NAME: name or ID of the user to be deleted
442     """
443 0     logger.debug("")
444 0     utils.check_client_version(ctx.obj, ctx.command.name)
445 0     ctx.obj.user.delete(name)
446
447
448 1 @click.command(name="user-list", short_help="list all users")
449 1 @click.option(
450     "--filter",
451     default=None,
452     multiple=True,
453     help="restricts the list to the users matching the filter",
454 )
455 1 @click.pass_context
456 1 def user_list(ctx, filter):
457     """list all users"""
458 0     utils.check_client_version(ctx.obj, ctx.command.name)
459 0     if filter:
460 0         filter = "&".join(filter)
461 0     resp, admin_show = ctx.obj.user.list(filter)
462 0     for user in resp:
463 0         if user["username"] == "admin":
464 0             user["_admin"]["account_expire_time"] = "N/A"
465 0     if admin_show:
466 0         table = PrettyTable(["name", "id", "user_status", "expires_in"])
467 0         for user in resp:
468 0             table.add_row(
469                 [
470                     user["username"],
471                     user["_id"],
472                     user["_admin"]["user_status"].upper(),
473                     (
474                         time.strftime(
475                             "%b-%d-%Y %X",
476                             time.gmtime(user["_admin"]["account_expire_time"]),
477                         )
478                         if not user["username"] == "admin"
479                         else user["_admin"]["account_expire_time"]
480                     ),
481                 ]
482             )
483     else:
484 0         table = PrettyTable(["name", "id"])
485 0         for user in resp:
486 0             table.add_row([user["username"], user["_id"]])
487 0     table.align = "l"
488 0     print(table)
489
490
491 1 @click.command(name="user-show", short_help="shows the details of a user")
492 1 @click.argument("name")
493 1 @click.pass_context
494 1 def user_show(ctx, name):
495     """shows the details of a user
496
497     NAME: name or ID of the user
498     """
499 0     logger.debug("")
500 0     utils.check_client_version(ctx.obj, ctx.command.name)
501 0     resp = ctx.obj.user.get(name)
502 0     if "password" in resp:
503 0         resp["password"] = "********"
504
505 0     table = PrettyTable(["key", "attribute"])
506 0     for k, v in resp.items():
507 0         table.add_row([k, json.dumps(v, indent=2)])
508 0     table.align = "l"
509 0     print(table)