import yaml
import json
import time
+import pycurl
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',
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 " +
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)
@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>["&"<simpleFilterExpr>]*
+ simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
+ 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
+ <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
+ "Op" stands for the comparison operator. If the expression has concatenated <attrName>
+ entries, it means that the operator "op" is applied to the attribute addressed by the last
+ <attrName> entry included in the concatenation. All simple filter expressions are combined
+ by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
+ 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=<NSD_NAME>
+ --filter nsd.vendor=<VENDOR>
+ --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
+ --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
+ '''
if filter:
check_client_version(ctx.obj, '--filter')
resp = ctx.obj.ns.list(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>["&"<simpleFilterExpr>]*
+ simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
+ 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
+ <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
+ "Op" stands for the comparison operator. If the expression has concatenated <attrName>
+ entries, it means that the operator "op" is applied to the attribute addressed by the last
+ <attrName> entry included in the concatenation. All simple filter expressions are combined
+ by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
+ 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=<VIM_ACCOUNT_ID>
+ --filter vnfd-ref=<VNFD_NAME>
+ --filter vdur.ip-address=<IP_ADDRESS>
+ --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<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:
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,
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,
####################
# VIM operations
####################
-
+
@cli.command(name='vim-create')
@click.option('--name',
prompt=True,
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
####################
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)
+