1 # Copyright ETSI Contributors and Others.
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
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, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
17 from osmclient
.common
.exceptions
import ClientException
18 from osmclient
.cli_commands
import utils
19 from prettytable
import PrettyTable
24 logger
= logging
.getLogger("osmclient")
27 ##############################
28 # Role Management Operations #
29 ##############################
32 @click.command(name
="role-create", short_help
="creates a new role")
33 @click.argument("name")
34 @click.option("--permissions", default
=None, help="role permissions using a dictionary")
36 def role_create(ctx
, name
, permissions
):
41 NAME: Name or ID of the role.
42 DEFINITION: Definition of grant/denial of access to resources.
45 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
46 ctx
.obj
.role
.create(name
, permissions
)
49 @click.command(name
="role-update", short_help
="updates a role")
50 @click.argument("name")
51 @click.option("--set-name", default
=None, help="change name of rle")
55 help="yaml format dictionary with permission: True/False to access grant/denial",
57 @click.option("--remove", default
=None, help="yaml format list to remove a permission")
59 def role_update(ctx
, name
, set_name
, add
, remove
):
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.
70 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
71 ctx
.obj
.role
.update(name
, set_name
, None, add
, remove
)
74 @click.command(name
="role-delete", short_help
="deletes a role")
75 @click.argument("name")
77 def role_delete(ctx
, name
):
82 NAME: Name or ID of the role.
85 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
86 ctx
.obj
.role
.delete(name
)
89 @click.command(name
="role-list", short_help
="list all roles")
94 help="restricts the list to the projects matching the filter",
97 def role_list(ctx
, filter):
102 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
104 filter = "&".join(filter)
105 resp
= ctx
.obj
.role
.list(filter)
106 table
= PrettyTable(["name", "id"])
108 table
.add_row([role
["name"], role
["_id"]])
113 @click.command(name
="role-show", short_help
="show specific role")
114 @click.argument("name")
116 def role_show(ctx
, name
):
118 Shows the details of a role.
121 NAME: Name or ID of the role.
124 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
125 resp
= ctx
.obj
.role
.get(name
)
127 table
= PrettyTable(["key", "attribute"])
128 for k
, v
in resp
.items():
129 table
.add_row([k
, json
.dumps(v
, indent
=2)])
135 # Project mgmt operations
139 @click.command(name
="project-create", short_help
="creates a new project")
140 @click.argument("name")
141 # @click.option('--description',
142 # default='no description',
143 # help='human readable description')
144 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
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",
154 def project_create(ctx
, name
, domain_name
, quotas
):
155 """Creates a new project
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
162 project
= {"name": name
}
164 project
["domain_name"] = domain_name
165 quotas_dict
= _process_project_quotas(quotas
)
167 project
["quotas"] = quotas_dict
169 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
170 ctx
.obj
.project
.create(name
, project
)
173 def _process_project_quotas(quota_list
):
178 for quota
in quota_list
:
179 for single_quota
in quota
.split(","):
180 k
, v
= single_quota
.split("=")
181 quotas_dict
[k
] = None if v
in ("None", "null", "") else int(v
)
182 except (ValueError, TypeError):
183 raise ClientException(
184 "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
189 @click.command(name
="project-delete", short_help
="deletes a project")
190 @click.argument("name")
192 def project_delete(ctx
, name
):
195 NAME: name or ID of the project to be deleted
198 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
199 ctx
.obj
.project
.delete(name
)
202 @click.command(name
="project-list", short_help
="list all projects")
207 help="restricts the list to the projects matching the filter",
210 def project_list(ctx
, filter):
211 """list all projects"""
213 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
215 filter = "&".join(filter)
216 resp
= ctx
.obj
.project
.list(filter)
217 table
= PrettyTable(["name", "id"])
219 table
.add_row([proj
["name"], proj
["_id"]])
224 @click.command(name
="project-show", short_help
="shows the details of a project")
225 @click.argument("name")
227 def project_show(ctx
, name
):
228 """shows the details of a project
230 NAME: name or ID of the project
233 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
234 resp
= ctx
.obj
.project
.get(name
)
236 table
= PrettyTable(["key", "attribute"])
237 for k
, v
in resp
.items():
238 table
.add_row([k
, json
.dumps(v
, indent
=2)])
244 name
="project-update", short_help
="updates a project (only the name can be updated)"
246 @click.argument("project")
247 @click.option("--name", default
=None, help="new name for the project")
253 help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
254 "(use empty to reset quota to default",
257 def project_update(ctx
, project
, name
, quotas
):
259 Update a project name
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
270 project_changes
["name"] = name
271 quotas_dict
= _process_project_quotas(quotas
)
273 project_changes
["quotas"] = quotas_dict
275 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
276 ctx
.obj
.project
.update(project
, project_changes
)
280 # User mgmt operations
284 @click.command(name
="user-create", short_help
="creates a new user")
285 @click.argument("username")
290 confirmation_prompt
=True,
291 help="user password",
295 # prompt="Comma separate list of projects",
297 callback
=lambda ctx
, param
, value
: (
298 "".join(value
).split(",") if all(len(x
) == 1 for x
in value
) else value
300 help="list of project ids that the user belongs to",
303 "--project-role-mappings",
304 "project_role_mappings",
307 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
309 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
311 def user_create(ctx
, username
, password
, projects
, project_role_mappings
, domain_name
):
312 """Creates a new user
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
323 user
["username"] = username
324 user
["password"] = password
325 user
["projects"] = projects
326 user
["project_role_mappings"] = project_role_mappings
328 user
["domain_name"] = domain_name
330 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
331 ctx
.obj
.user
.create(username
, user
)
334 @click.command(name
="user-update", short_help
="updates user information")
335 @click.argument("username")
336 @click.option("--set-username", "set_username", default
=None, help="change username")
342 help="create/replace the roles for this project: 'project,role1[,role2,...]'",
349 help="removes project from user: 'project'",
352 "--add-project-role",
356 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
359 "--remove-project-role",
360 "remove_project_role",
363 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
365 @click.option("--current-password", "current_password", help="user's current password")
371 # confirmation_prompt=True,
372 help="new user password",
398 """Update a user information
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
414 user
["username"] = set_username
415 user
["set-project"] = set_project
416 user
["remove-project"] = remove_project
417 user
["add-project-role"] = add_project_role
418 user
["remove-project-role"] = remove_project_role
419 user
["current_password"] = current_password
420 user
["new_password"] = new_password
421 user
["unlock"] = unlock
422 user
["renew"] = renew
424 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
425 if not user
.get("current_password"):
426 # In case the password is valid but the end user wants to update it
427 ctx
.obj
.user
.update(username
, user
)
429 # In case the password has expired (also applies in first login)
430 ctx
.obj
.user
.update(username
, user
, pwd_change
=True)
433 @click.command(name
="user-delete", short_help
="deletes a user")
434 @click.argument("name")
435 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
437 def user_delete(ctx
, name
):
441 NAME: name or ID of the user to be deleted
444 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
445 ctx
.obj
.user
.delete(name
)
448 @click.command(name
="user-list", short_help
="list all users")
453 help="restricts the list to the users matching the filter",
456 def user_list(ctx
, filter):
458 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
460 filter = "&".join(filter)
461 resp
, admin_show
= ctx
.obj
.user
.list(filter)
463 if user
["username"] == "admin":
464 user
["_admin"]["account_expire_time"] = "N/A"
466 table
= PrettyTable(["name", "id", "user_status", "expires_in"])
472 user
["_admin"]["user_status"].upper(),
476 time
.gmtime(user
["_admin"]["account_expire_time"]),
478 if not user
["username"] == "admin"
479 else user
["_admin"]["account_expire_time"]
484 table
= PrettyTable(["name", "id"])
486 table
.add_row([user
["username"], user
["_id"]])
491 @click.command(name
="user-show", short_help
="shows the details of a user")
492 @click.argument("name")
494 def user_show(ctx
, name
):
495 """shows the details of a user
497 NAME: name or ID of the user
500 utils
.check_client_version(ctx
.obj
, ctx
.command
.name
)
501 resp
= ctx
.obj
.user
.get(name
)
502 if "password" in resp
:
503 resp
["password"] = "********"
505 table
= PrettyTable(["key", "attribute"])
506 for k
, v
in resp
.items():
507 table
.add_row([k
, json
.dumps(v
, indent
=2)])