X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osmclient%2Fscripts%2Fosm.py;h=c07b62ddd12d3dd3d503b3d1524e6818ac2dae1b;hb=6991001536f5cd7b4bda5d9c95e09646048cf9f3;hp=601d42825e6573cb04c49951b0cadc225e97603e;hpb=feec9cb6a4e2865292aa23b7b6f89e4120da76e5;p=osm%2Fosmclient.git diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index 601d428..c07b62d 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -25,6 +25,7 @@ from prettytable import PrettyTable import yaml import json import time +import pycurl def check_client_version(obj, what, version='sol005'): ''' @@ -45,10 +46,30 @@ def check_client_version(obj, what, version='sol005'): @click.group() @click.option('--hostname', - default=None, + default="127.0.0.1", envvar='OSM_HOSTNAME', help='hostname of server. ' + 'Also can set OSM_HOSTNAME in environment') +@click.option('--sol005/--no-sol005', + default=True, + envvar='OSM_SOL005', + help='Use ETSI NFV SOL005 API (default) or the previous SO API. ' + + 'Also can set OSM_SOL005 in environment') +@click.option('--user', + default=None, + envvar='OSM_USER', + help='user (only from Release FOUR, defaults to admin). ' + + 'Also can set OSM_USER in environment') +@click.option('--password', + default=None, + envvar='OSM_PASSWORD', + help='password (only from Release FOUR, defaults to admin). ' + + 'Also can set OSM_PASSWORD in environment') +@click.option('--project', + default=None, + envvar='OSM_PROJECT', + help='project (only from Release FOUR, defaults to admin). ' + + 'Also can set OSM_PROJECT in environment') @click.option('--so-port', default=None, envvar='OSM_SO_PORT', @@ -65,16 +86,12 @@ def check_client_version(obj, what, version='sol005'): help='hostname of RO server. ' + 'Also can set OSM_RO_HOSTNAME in environment') @click.option('--ro-port', - default=9090, + default=None, envvar='OSM_RO_PORT', help='hostname of RO server. ' + 'Also can set OSM_RO_PORT in environment') -@click.option('--sol005/--no-sol005', - default=True, - envvar='OSM_SOL005', - help='Use ETSI NFV SOL005 API (default) or the previous SO API') @click.pass_context -def cli(ctx, hostname, so_port, so_project, ro_hostname, ro_port, sol005): +def cli(ctx, hostname, sol005, user, password, project, so_port, so_project, ro_hostname, ro_port): if hostname is None: print(( "either hostname option or OSM_HOSTNAME " + @@ -89,7 +106,13 @@ def cli(ctx, hostname, so_port, so_project, ro_hostname, ro_port, sol005): kwargs['ro_host']=ro_hostname if ro_port is not None: kwargs['ro_port']=ro_port - + if user is not None: + kwargs['user']=user + if password is not None: + kwargs['password']=password + if project is not None: + kwargs['project']=project + ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs) @@ -99,10 +122,56 @@ def cli(ctx, hostname, so_port, so_project, ro_hostname, ro_port, sol005): @cli.command(name='ns-list') @click.option('--filter', default=None, - help='restricts the list to the NS instances matching the filter') + help='restricts the list to the NS instances matching the filter.') @click.pass_context def ns_list(ctx, filter): - '''list all NS instances''' + '''list all NS instances + + \b + Options: + --filter filterExpr Restricts the list to the NS instances matching the filter + + \b + filterExpr consists of one or more strings formatted according to "simpleFilterExpr", + concatenated using the "&" character: + + \b + filterExpr := ["&"]* + simpleFilterExpr := ["."]*["."]"="[","]* + op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont" + attrName := string + value := scalar value + + \b + where: + * zero or more occurrences + ? zero or one occurrence + [] grouping of expressions to be used with ? and * + "" quotation marks for marking string constants + <> name separator + + \b + "AttrName" is the name of one attribute in the data type that defines the representation + of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of + entries to filter by attributes deeper in the hierarchy of a structured document. + "Op" stands for the comparison operator. If the expression has concatenated + entries, it means that the operator "op" is applied to the attribute addressed by the last + entry included in the concatenation. All simple filter expressions are combined + by the "AND" logical operator. In a concatenation of entries in a , + the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The + concatenation of all "attrName" entries except the leaf attribute is called the "attribute + prefix". If an attribute referenced in an expression is an array, an object that contains a + corresponding array shall be considered to match the expression if any of the elements in the + array matches all expressions that have the same attribute prefix. + + \b + Filter examples: + --filter admin-status=ENABLED + --filter nsd-ref= + --filter nsd.vendor= + --filter nsd.vendor=&nsd-ref= + --filter nsd.constituent-vnfd.vnfd-id-ref= + ''' if filter: check_client_version(ctx.obj, '--filter') resp = ctx.obj.ns.list(filter) @@ -218,13 +287,64 @@ def vnfd_list2(ctx, filter): @cli.command(name='vnf-list') @click.option('--ns', default=None, help='NS instance id or name to restrict the VNF list') +@click.option('--filter', default=None, + help='restricts the list to the VNF instances matching the filter.') @click.pass_context -def vnf_list(ctx, ns): - ''' list all VNF instances''' +def vnf_list(ctx, ns, filter): + '''list all VNF instances + + \b + Options: + --ns TEXT NS instance id or name to restrict the VNF list + --filter filterExpr Restricts the list to the VNF instances matching the filter + + \b + filterExpr consists of one or more strings formatted according to "simpleFilterExpr", + concatenated using the "&" character: + + \b + filterExpr := ["&"]* + simpleFilterExpr := ["."]*["."]"="[","]* + op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont" + attrName := string + value := scalar value + + \b + where: + * zero or more occurrences + ? zero or one occurrence + [] grouping of expressions to be used with ? and * + "" quotation marks for marking string constants + <> name separator + + \b + "AttrName" is the name of one attribute in the data type that defines the representation + of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of + entries to filter by attributes deeper in the hierarchy of a structured document. + "Op" stands for the comparison operator. If the expression has concatenated + entries, it means that the operator "op" is applied to the attribute addressed by the last + entry included in the concatenation. All simple filter expressions are combined + by the "AND" logical operator. In a concatenation of entries in a , + the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The + concatenation of all "attrName" entries except the leaf attribute is called the "attribute + prefix". If an attribute referenced in an expression is an array, an object that contains a + corresponding array shall be considered to match the expression if any of the elements in the + array matches all expressions that have the same attribute prefix. + + \b + Filter examples: + --filter vim-account-id= + --filter vnfd-ref= + --filter vdur.ip-address= + --filter vnfd-ref=,vdur.ip-address= + ''' try: - if ns: - check_client_version(ctx.obj, '--ns') - resp = ctx.obj.vnf.list(ns) + if ns or filter: + if ns: + check_client_version(ctx.obj, '--ns') + if filter: + check_client_version(ctx.obj, '--filter') + resp = ctx.obj.vnf.list(ns, filter) else: resp = ctx.obj.vnf.list() except ClientException as inst: @@ -607,11 +727,13 @@ def vnfd_create2(ctx, filename, overwrite): help='administration status') @click.option('--ssh_keys', default=None, - help='comma separated list of keys to inject to vnfs') + help='comma separated list of public key files to inject to vnfs') @click.option('--config', default=None, - help='ns specific yaml configuration:\nvnf: [member-vnf-index: TEXT, vim_account: TEXT]\n' - 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]') + help='ns specific yaml configuration') +@click.option('--config_file', + default=None, + help='ns specific yaml configuration file') @click.pass_context def ns_create(ctx, nsd_name, @@ -619,11 +741,16 @@ def ns_create(ctx, vim_account, admin_status, ssh_keys, - config): + config, + config_file): '''creates a new NS instance''' try: - # if config: - # check_client_version(ctx.obj, '--config', 'v1') + if config_file: + check_client_version(ctx.obj, '--config_file') + if config: + raise ClientException('"--config" option is incompatible with "--config_file" option') + with open(config_file, 'r') as cf: + config=cf.read() ctx.obj.ns.create( nsd_name, ns_name, @@ -807,7 +934,7 @@ def ns_delete(ctx, name, force): #################### # VIM operations #################### - + @cli.command(name='vim-create') @click.option('--name', prompt=True, @@ -1164,6 +1291,182 @@ def sdnc_show(ctx, name): print(table) +#################### +# Project mgmt operations +#################### + +@cli.command(name='project-create') +@click.argument('name') +#@click.option('--description', +# default='no description', +# help='human readable description') +@click.pass_context +def project_create(ctx, name): + '''Creates a new project + + NAME: name of the project + ''' + project = {} + project['name'] = name + try: + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.project.create(name, project) + except ClientException as inst: + print(inst.message) + + +@cli.command(name='project-delete') +@click.argument('name') +#@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions') +@click.pass_context +def project_delete(ctx, name): + '''deletes a project + + NAME: name or ID of the project to be deleted + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.project.delete(name) + except ClientException as inst: + print(inst.message) + exit(1) + + +@cli.command(name='project-list') +@click.option('--filter', default=None, + help='restricts the list to the projects matching the filter') +@click.pass_context +def project_list(ctx, filter): + '''list all projects''' + try: + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.project.list(filter) + except ClientException as inst: + print(inst.message) + exit(1) + table = PrettyTable(['name', 'id']) + for proj in resp: + table.add_row([proj['name'], proj['_id']]) + table.align = 'l' + print(table) + + +@cli.command(name='project-show') +@click.argument('name') +@click.pass_context +def project_show(ctx, name): + '''shows the details of a project + + NAME: name or ID of the project + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.project.get(name) + except ClientException as inst: + print(inst.message) + exit(1) + + table = PrettyTable(['key', 'attribute']) + for k, v in resp.items(): + table.add_row([k, json.dumps(v, indent=2)]) + table.align = 'l' + print(table) + + +#################### +# User mgmt operations +#################### + +@cli.command(name='user-create') +@click.argument('username') +@click.option('--password', + prompt=True, + hide_input=True, + confirmation_prompt=True, + help='user password') +@click.option('--projects', + default=None, + help='list of project ids that the user belongs to') +#@click.option('--description', +# default='no description', +# help='human readable description') +@click.pass_context +def user_create(ctx, username, password, projects): + '''Creates a new user + + USERNAME: name of the user + ''' + user = {} + user['username'] = username + user['password'] = password + user['projects'] = projects + try: + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.user.create(username, user) + except ClientException as inst: + print(inst.message) + + +@cli.command(name='user-delete') +@click.argument('name') +#@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions') +@click.pass_context +def user_delete(ctx, name): + '''deletes a user + + NAME: name or ID of the user to be deleted + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.user.delete(name) + except ClientException as inst: + print(inst.message) + exit(1) + + +@cli.command(name='user-list') +@click.option('--filter', default=None, + help='restricts the list to the users matching the filter') +@click.pass_context +def user_list(ctx, filter): + '''list all users''' + try: + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.user.list(filter) + except ClientException as inst: + print(inst.message) + exit(1) + table = PrettyTable(['name', 'id']) + for user in resp: + table.add_row([user['name'], user['_id']]) + table.align = 'l' + print(table) + + +@cli.command(name='user-show') +@click.argument('name') +@click.pass_context +def user_show(ctx, name): + '''shows the details of a user + + NAME: name or ID of the user + ''' + try: + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.user.get(name) + if 'password' in resp: + resp['password']='********' + except ClientException as inst: + print(inst.message) + exit(1) + + table = PrettyTable(['key', 'attribute']) + for k, v in resp.items(): + table.add_row([k, json.dumps(v, indent=2)]) + table.align = 'l' + print(table) + + #################### # Fault Management operations #################### @@ -1462,45 +1765,41 @@ def ns_action(ctx, exit(1) -@cli.command(name='ns-scale-vdu') -@click.argument('ns_name' ) -@click.option('--vnf-name', prompt=True, help="member-vnf-index to scale") +@cli.command(name='vnf-scale') +@click.argument('ns_name') +@click.argument('vnf_name') @click.option('--scaling-group', prompt=True, help="scaling-group-descriptor name to use") @click.option('--scale-in', default=False, is_flag=True, help="performs a scale in operation") @click.option('--scale-out', default=False, is_flag=True, help="performs a scale out operation (by default)") @click.pass_context -def ns_scale_vdu(ctx, +def vnf_scale(ctx, ns_name, vnf_name, scaling_group, scale_in, scale_out): - """executes a VNF VDU scale over a NS instance + '''executes a VNF scale (adding/removing VDUs) - NS_NAME: name or ID of the NS instance - """ + \b + NS_NAME: name or ID of the NS instance. + VNF_NAME: member-vnf-index in the NS to be scaled. + ''' try: check_client_version(ctx.obj, ctx.command.name) - op_data={} if not scale_in and not scale_out: scale_out = True - # print("You must provide scale type with option '--vnf-scale-in' or '--vnf-scale-out'") - # exit(1) - op_data["scaleType"] = "SCALE_VNF" - op_data["scaleVnfData"] = {} - if scale_in: - op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_IN" - else: - op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT" - op_data["scaleVnfData"]["scaleByStepData"] = { - "member-vnf-index": vnf_name, - "scaling-group-descriptor": scaling_group, - } - ctx.obj.ns.exec_op(ns_name, op_name='scale', op_data=op_data) + ctx.obj.ns.scale_vnf(ns_name, vnf_name, scaling_group, scale_in, scale_out) except ClientException as inst: print((inst.message)) exit(1) if __name__ == '__main__': - cli() + try: + cli() + except pycurl.error as e: + print(e) + print('Maybe "--hostname" option or OSM_HOSTNAME' + + 'environment variable needs to be specified') + exit(1) +