Merge branch 'master' into v7.0
[osm/osmclient.git] / osmclient / scripts / osm.py
index 4cc451b..f61373e 100755 (executable)
@@ -29,8 +29,14 @@ import pycurl
 import os
 import textwrap
 import pkg_resources
+import logging
+from datetime import datetime
 
 
+# Global variables
+
+CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=160)
+
 def wrap_text(text, width):
     wrapper = textwrap.TextWrapper(width=width)
     lines = text.splitlines()
@@ -53,6 +59,7 @@ def check_client_version(obj, what, version='sol005'):
     :return: -
     :raises ClientError: if the specified version does not match the client version
     """
+    logger.debug("")
     fullclassname = obj.__module__ + "." + obj.__class__.__name__
     message = 'The following commands or options are only supported with the option "--sol005": {}'.format(what)
     if version == 'v1':
@@ -62,9 +69,7 @@ def check_client_version(obj, what, version='sol005'):
     return
 
 
-CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=160)
-
-@click.group(context_settings=CONTEXT_SETTINGS)
+@click.group(context_settings=dict(help_option_names=['-h', '--help'], max_content_width=160))
 @click.option('--hostname',
               default="127.0.0.1",
               envvar='OSM_HOSTNAME',
@@ -90,6 +95,8 @@ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=16
               envvar='OSM_PROJECT',
               help='project (defaults to admin). ' +
                    'Also can set OSM_PROJECT in environment')
+@click.option('-v', '--verbose', count=True,
+              help='increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)')
 #@click.option('--so-port',
 #              default=None,
 #              envvar='OSM_SO_PORT',
@@ -111,13 +118,14 @@ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=16
 #              help='hostname of RO server.  ' +
 #                   'Also can set OSM_RO_PORT in environment')
 @click.pass_context
-def cli_osm(ctx, hostname, user, password, project):
+def cli_osm(ctx, hostname, user, password, project, verbose):
+    global logger
     if hostname is None:
         print((
             "either hostname option or OSM_HOSTNAME " +
             "environment variable needs to be specified"))
         exit(1)
-    kwargs={}
+    kwargs = {'verbose': verbose}
 #    if so_port is not None:
 #        kwargs['so_port']=so_port
 #    if so_project is not None:
@@ -134,6 +142,7 @@ def cli_osm(ctx, hostname, user, password, project):
     if project is not None:
         kwargs['project']=project
     ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs)
+    logger = logging.getLogger('osmclient')
 
 
 ####################
@@ -143,8 +152,10 @@ def cli_osm(ctx, hostname, user, password, project):
 @cli_osm.command(name='ns-list', short_help='list all NS instances')
 @click.option('--filter', default=None,
               help='restricts the list to the NS instances matching the filter.')
+@click.option('--details', is_flag=True,
+              help='get more details of current operation in the NS.')
 @click.pass_context
-def ns_list(ctx, filter):
+def ns_list(ctx, filter,details):
     """list all NS instances
 
     \b
@@ -192,46 +203,155 @@ def ns_list(ctx, filter):
        --filter  nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
        --filter  nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
     """
+    def summarize_deployment_status(status_dict):
+        #Nets
+        summary = ""
+        n_nets = 0
+        status_nets = {}
+        net_list = status_dict['nets']
+        for net in net_list:
+            n_nets += 1
+            if net['status'] not in status_nets:
+                status_nets[net['status']] = 1
+            else:
+                status_nets[net['status']] +=1
+        message = "Nets: "
+        for k,v in status_nets.items():
+            message += "{}:{},".format(k,v)
+        message += "TOTAL:{}".format(n_nets)
+        summary += "{}".format(message)
+        #VMs and VNFs
+        n_vms = 0
+        status_vms = {}
+        status_vnfs = {}
+        vnf_list = status_dict['vnfs']
+        for vnf in vnf_list:
+            member_vnf_index = vnf['member_vnf_index']
+            if member_vnf_index not in status_vnfs:
+                status_vnfs[member_vnf_index] = {}
+            for vm in vnf['vms']:
+                n_vms += 1
+                if vm['status'] not in status_vms:
+                    status_vms[vm['status']] = 1
+                else:
+                    status_vms[vm['status']] +=1
+                if vm['status'] not in status_vnfs[member_vnf_index]:
+                    status_vnfs[member_vnf_index][vm['status']] = 1
+                else:
+                    status_vnfs[member_vnf_index][vm['status']] += 1
+        message = "VMs: "
+        for k,v in status_vms.items():
+            message += "{}:{},".format(k,v)
+        message += "TOTAL:{}".format(n_vms)
+        summary += "\n{}".format(message)
+        summary += "\nNFs:"
+        for k,v in status_vnfs.items():
+            total = 0
+            message = "\n  {} VMs: ".format(k)
+            for k2,v2 in v.items():
+                message += "{}:{},".format(k2,v2)
+                total += v2
+            message += "TOTAL:{}".format(total)
+        summary += message
+        return summary
+        
+    def summarize_config_status(ee_list):
+        n_ee = 0
+        status_ee = {}
+        for ee in ee_list:
+            n_ee += 1
+            if ee['elementType'] not in status_ee:
+                status_ee[ee['elementType']] = {}
+                status_ee[ee['elementType']][ee['status']] = 1
+                continue;
+            if ee['status'] in status_ee[ee['elementType']]:
+                status_ee[ee['elementType']][ee['status']] += 1
+            else:
+                status_ee[ee['elementType']][ee['status']] = 1
+        summary = ""
+        for elementType in ["KDU", "VDU", "PDU", "VNF", "NS"]:
+            if elementType in status_ee:
+                message = ""
+                total = 0
+                for k,v in status_ee[elementType].items():
+                    message += "{}:{},".format(k,v)
+                    total += v
+                message += "TOTAL:{}\n".format(total)
+                summary += "{}: {}".format(elementType, message)
+        summary += "TOTAL Exec. Env.: {}".format(n_ee)
+        return summary
+    logger.debug("")
     if filter:
         check_client_version(ctx.obj, '--filter')
         resp = ctx.obj.ns.list(filter)
     else:
         resp = ctx.obj.ns.list()
-    table = PrettyTable(
+    if details:
+        table = PrettyTable(
         ['ns instance name',
          'id',
-         'operational status',
-         'config status',
-         'detailed status'])
+         'ns state',
+         'current operation',
+         'error details',
+         'deployment status',
+         'configuration status'])
+    else:
+        table = PrettyTable(
+        ['ns instance name',
+         'id',
+         'ns state',
+         'current operation',
+         'error details'])
     for ns in resp:
         fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
         if fullclassname == 'osmclient.sol005.client.Client':
             nsr = ns
             nsr_name = nsr['name']
             nsr_id = nsr['_id']
+            ns_state = nsr['nsState']
+            if details:
+                deployment_status = summarize_deployment_status(nsr['deploymentStatus'])
+                config_status = summarize_config_status(nsr['configurationStatus'])
+            current_operation = "{} ({})".format(nsr['currentOperation'],nsr['currentOperationID'])
+            error_details = "N/A"
+            if ns_state == "BROKEN" or ns_state == "DEGRADED":
+                error_details = "{}\nDetail: {}".format(nsr['errorDescription'],nsr['errorDetail'])
         else:
             nsopdata = ctx.obj.ns.get_opdata(ns['id'])
             nsr = nsopdata['nsr:nsr']
             nsr_name = nsr['name-ref']
             nsr_id = nsr['ns-instance-config-ref']
-        opstatus = nsr['operational-status'] if 'operational-status' in nsr else 'Not found'
-        configstatus = nsr['config-status'] if 'config-status' in nsr else 'Not found'
-        detailed_status = nsr['detailed-status'] if 'detailed-status' in nsr else 'Not found'
-        detailed_status = wrap_text(text=detailed_status,width=50)
-        if configstatus == "config_not_needed":
-            configstatus = "configured (no charms)"
-
-        table.add_row(
-            [nsr_name,
-             nsr_id,
-             opstatus,
-             configstatus,
-             detailed_status])
+            deployment_status = nsr['operational-status'] if 'operational-status' in nsr else 'Not found'
+            ns_state = deployment_status
+            config_status = nsr['config-status'] if 'config-status' in nsr else 'Not found'
+            current_operation = "Unknown"
+            error_details = nsr['detailed-status'] if 'detailed-status' in nsr else 'Not found'
+            if config_status == "config_not_needed":
+                config_status = "configured (no charms)"
+
+        if details:
+            table.add_row(
+                 [nsr_name,
+                 nsr_id,
+                 ns_state,
+                 current_operation,
+                 wrap_text(text=error_details,width=40),
+                 deployment_status,
+                 config_status])
+        else:
+            table.add_row(
+                 [nsr_name,
+                 nsr_id,
+                 ns_state,
+                 current_operation,
+                 wrap_text(text=error_details,width=40)])
     table.align = 'l'
     print(table)
-
+    print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
+    print('For more details on the current operation, run "osm ns-op-show OPERATION_ID"')
 
 def nsd_list(ctx, filter):
+    logger.debug("")
     if filter:
         check_client_version(ctx.obj, '--filter')
         resp = ctx.obj.nsd.list(filter)
@@ -257,6 +377,7 @@ def nsd_list(ctx, filter):
 @click.pass_context
 def nsd_list1(ctx, filter):
     """list all NSD/NS pkg in the system"""
+    logger.debug("")
     nsd_list(ctx, filter)
 
 
@@ -266,10 +387,12 @@ def nsd_list1(ctx, filter):
 @click.pass_context
 def nsd_list2(ctx, filter):
     """list all NS packages"""
+    logger.debug("")
     nsd_list(ctx, filter)
 
 
 def vnfd_list(ctx, nf_type, filter):
+    logger.debug("")
     if nf_type:
         check_client_version(ctx.obj, '--nf_type')
     elif filter:
@@ -312,6 +435,7 @@ def vnfd_list(ctx, nf_type, filter):
 @click.pass_context
 def vnfd_list1(ctx, nf_type, filter):
     """list all xNF packages (VNF, HNF, PNF)"""
+    logger.debug("")
     vnfd_list(ctx, nf_type, filter)
 
 
@@ -322,6 +446,7 @@ def vnfd_list1(ctx, nf_type, filter):
 @click.pass_context
 def vnfd_list2(ctx, nf_type, filter):
     """list all xNF packages (VNF, HNF, PNF)"""
+    logger.debug("")
     vnfd_list(ctx, nf_type, filter)
 
 
@@ -332,6 +457,7 @@ def vnfd_list2(ctx, nf_type, filter):
 @click.pass_context
 def nfpkg_list(ctx, nf_type, filter):
     """list all xNF packages (VNF, HNF, PNF)"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     vnfd_list(ctx, nf_type, filter)
@@ -399,6 +525,7 @@ def vnf_list(ctx, ns, filter):
 @click.pass_context
 def vnf_list1(ctx, ns, filter):
     """list all NF instances"""
+    logger.debug("")
     vnf_list(ctx, ns, filter)
 
 
@@ -455,6 +582,7 @@ def nf_list(ctx, ns, filter):
        --filter  vdur.ip-address=<IP_ADDRESS>
        --filter  vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
     """
+    logger.debug("")
     vnf_list(ctx, ns, filter)
 
 
@@ -466,6 +594,19 @@ def ns_op_list(ctx, name):
 
     NAME: name or ID of the NS instance
     """
+    def formatParams(params):
+        if params['lcmOperationType']=='instantiate':
+            params.pop('nsDescription')
+            params.pop('nsName')
+            params.pop('nsdId')
+            params.pop('nsr_id')
+        elif params['lcmOperationType']=='action':
+            params.pop('primitive')
+        params.pop('lcmOperationType')
+        params.pop('nsInstanceId')
+        return params
+
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.ns.list_op(name)
@@ -473,20 +614,34 @@ def ns_op_list(ctx, name):
     #     print(str(e))
     #     exit(1)
 
-    table = PrettyTable(['id', 'operation', 'action_name', 'status'])
+    table = PrettyTable(['id', 'operation', 'action_name', 'operation_params', 'status', 'detail'])
     #print(yaml.safe_dump(resp))
     for op in resp:
         action_name = "N/A"
         if op['lcmOperationType']=='action':
             action_name = op['operationParams']['primitive']
-        table.add_row([op['id'], op['lcmOperationType'], action_name,
-                       op['operationState']])
+        detail = "-"
+        if op['operationState']=='PROCESSING':
+            if op['lcmOperationType']=='instantiate':
+                if op['stage']:
+                    detail = op['stage']
+            else:
+                detail = "In queue. Current position: {}".format(op['queuePosition'])
+        elif op['operationState']=='FAILED' or op['operationState']=='FAILED_TEMP':
+            detail = op['errorMessage']
+        table.add_row([op['id'],
+                      op['lcmOperationType'],
+                      action_name,
+                      wrap_text(text=json.dumps(formatParams(op['operationParams']),indent=2),width=70),
+                      op['operationState'],
+                      wrap_text(text=detail,width=50)])
     table.align = 'l'
     print(table)
 
 
 def nsi_list(ctx, filter):
     """list all Network Slice Instances"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.nsi.list(filter)
@@ -523,6 +678,7 @@ def nsi_list(ctx, filter):
 @click.pass_context
 def nsi_list1(ctx, filter):
     """list all Network Slice Instances (NSI)"""
+    logger.debug("")
     nsi_list(ctx, filter)
 
 
@@ -532,10 +688,12 @@ def nsi_list1(ctx, filter):
 @click.pass_context
 def nsi_list2(ctx, filter):
     """list all Network Slice Instances (NSI)"""
+    logger.debug("")
     nsi_list(ctx, filter)
 
 
 def nst_list(ctx, filter):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.nst.list(filter)
@@ -557,6 +715,7 @@ def nst_list(ctx, filter):
 @click.pass_context
 def nst_list1(ctx, filter):
     """list all Network Slice Templates (NST) in the system"""
+    logger.debug("")
     nst_list(ctx, filter)
 
 
@@ -566,10 +725,12 @@ def nst_list1(ctx, filter):
 @click.pass_context
 def nst_list2(ctx, filter):
     """list all Network Slice Templates (NST) in the system"""
+    logger.debug("")
     nst_list(ctx, filter)
 
 
 def nsi_op_list(ctx, name):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.nsi.list_op(name)
@@ -592,6 +753,7 @@ def nsi_op_list1(ctx, name):
 
     NAME: name or ID of the Network Slice Instance
     """
+    logger.debug("")
     nsi_op_list(ctx, name)
 
 
@@ -603,6 +765,7 @@ def nsi_op_list2(ctx, name):
 
     NAME: name or ID of the Network Slice Instance
     """
+    logger.debug("")
     nsi_op_list(ctx, name)
 
 
@@ -612,6 +775,7 @@ def nsi_op_list2(ctx, name):
 @click.pass_context
 def pdu_list(ctx, filter):
     """list all Physical Deployment Units (PDU)"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.pdu.list(filter)
@@ -646,6 +810,7 @@ def pdu_list(ctx, filter):
 ####################
 
 def nsd_show(ctx, name, literal):
+    logger.debug("")
     # try:
     resp = ctx.obj.nsd.get(name)
     # resp = ctx.obj.nsd.get_individual(name)
@@ -674,6 +839,7 @@ def nsd_show1(ctx, name, literal):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nsd_show(ctx, name, literal)
 
 
@@ -687,10 +853,12 @@ def nsd_show2(ctx, name, literal):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nsd_show(ctx, name, literal)
 
 
 def vnfd_show(ctx, name, literal):
+    logger.debug("")
     # try:
     resp = ctx.obj.vnfd.get(name)
     # resp = ctx.obj.vnfd.get_individual(name)
@@ -719,6 +887,7 @@ def vnfd_show1(ctx, name, literal):
 
     NAME: name or ID of the VNFD/VNFpkg
     """
+    logger.debug("")
     vnfd_show(ctx, name, literal)
 
 
@@ -732,6 +901,7 @@ def vnfd_show2(ctx, name, literal):
 
     NAME: name or ID of the VNFD/VNFpkg
     """
+    logger.debug("")
     vnfd_show(ctx, name, literal)
 
 
@@ -745,6 +915,7 @@ def nfpkg_show(ctx, name, literal):
 
     NAME: name or ID of the NFpkg
     """
+    logger.debug("")
     vnfd_show(ctx, name, literal)
 
 
@@ -759,6 +930,7 @@ def ns_show(ctx, name, literal, filter):
 
     NAME: name or ID of the NS instance
     """
+    logger.debug("")
     # try:
     ns = ctx.obj.ns.get(name)
     # except ClientException as e:
@@ -798,6 +970,33 @@ def vnf_show(ctx, name, literal, filter, kdu):
 
     NAME: name or ID of the VNF instance
     """
+    def print_kdu_status(op_info_status):
+        """print KDU status properly formatted
+        """
+        try:
+            op_status = yaml.safe_load(op_info_status)
+            if "namespace" in op_status and "info" in op_status and \
+            "last_deployed" in op_status["info"] and "status" in op_status["info"] and \
+            "code" in op_status["info"]["status"] and "resources" in op_status["info"]["status"] and \
+            "notes" in op_status["info"]["status"] and "seconds" in op_status["info"]["last_deployed"]:
+                last_deployed_time = datetime.fromtimestamp(op_status["info"]["last_deployed"]["seconds"]).strftime("%a %b %d %I:%M:%S %Y")
+                print("LAST DEPLOYED: {}".format(last_deployed_time))
+                print("NAMESPACE: {}".format(op_status["namespace"]))
+                status_code = "UNKNOWN"
+                if op_status["info"]["status"]["code"]==1:
+                    status_code = "DEPLOYED"
+                print("STATUS: {}".format(status_code))
+                print()
+                print("RESOURCES:")
+                print(op_status["info"]["status"]["resources"])
+                print("NOTES:")
+                print(op_status["info"]["status"]["notes"])
+            else:
+                print(op_info_status)
+        except Exception:
+            print(op_info_status)
+
+    logger.debug("")
     if kdu:
         if literal:
             raise ClientException('"--literal" option is incompatible with "--kdu" option')
@@ -820,7 +1019,7 @@ def vnf_show(ctx, name, literal, filter, kdu):
         while t<30:
             op_info = ctx.obj.ns.get_op(op_id)
             if op_info['operationState'] == 'COMPLETED':
-                print(op_info['detailed-status'])
+                print_kdu_status(op_info['detailed-status'])
                 return
             time.sleep(5)
             t += 5
@@ -899,6 +1098,7 @@ def ns_op_show(ctx, id, filter, literal):
 
     ID: operation identifier
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     op_info = ctx.obj.ns.get_op(id)
@@ -919,6 +1119,7 @@ def ns_op_show(ctx, id, filter, literal):
 
 
 def nst_show(ctx, name, literal):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.nst.get(name)
@@ -948,6 +1149,7 @@ def nst_show1(ctx, name, literal):
 
     NAME: name or ID of the NST
     """
+    logger.debug("")
     nst_show(ctx, name, literal)
 
 
@@ -961,10 +1163,12 @@ def nst_show2(ctx, name, literal):
 
     NAME: name or ID of the NST
     """
+    logger.debug("")
     nst_show(ctx, name, literal)
 
 
 def nsi_show(ctx, name, literal, filter):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     nsi = ctx.obj.nsi.get(name)
@@ -997,6 +1201,7 @@ def nsi_show1(ctx, name, literal, filter):
 
     NAME: name or ID of the Network Slice Instance
     """
+    logger.debug("")
     nsi_show(ctx, name, literal, filter)
 
 
@@ -1011,10 +1216,12 @@ def nsi_show2(ctx, name, literal, filter):
 
     NAME: name or ID of the Network Slice Instance
     """
+    logger.debug("")
     nsi_show(ctx, name, literal, filter)
 
 
 def nsi_op_show(ctx, id, filter):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     op_info = ctx.obj.nsi.get_op(id)
@@ -1039,6 +1246,7 @@ def nsi_op_show1(ctx, id, filter):
 
     ID: operation identifier
     """
+    logger.debug("")
     nsi_op_show(ctx, id, filter)
 
 
@@ -1051,6 +1259,7 @@ def nsi_op_show2(ctx, id, filter):
 
     ID: operation identifier
     """
+    logger.debug("")
     nsi_op_show(ctx, id, filter)
 
 
@@ -1065,6 +1274,7 @@ def pdu_show(ctx, name, literal, filter):
 
     NAME: name or ID of the PDU
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     pdu = ctx.obj.pdu.get(name)
@@ -1091,6 +1301,7 @@ def pdu_show(ctx, name, literal, filter):
 ####################
 
 def nsd_create(ctx, filename, overwrite):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nsd.create(filename, overwrite)
@@ -1101,7 +1312,7 @@ def nsd_create(ctx, filename, overwrite):
 
 @cli_osm.command(name='nsd-create', short_help='creates a new NSD/NSpkg')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1112,12 +1323,13 @@ def nsd_create1(ctx, filename, overwrite):
 
     FILENAME: NSD yaml file or NSpkg tar.gz file
     """
+    logger.debug("")
     nsd_create(ctx, filename, overwrite)
 
 
 @cli_osm.command(name='nspkg-create', short_help='creates a new NSD/NSpkg')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1128,10 +1340,12 @@ def nsd_create2(ctx, filename, overwrite):
 
     FILENAME: NSD yaml file or NSpkg tar.gz file
     """
+    logger.debug("")
     nsd_create(ctx, filename, overwrite)
 
 
 def vnfd_create(ctx, filename, overwrite):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.vnfd.create(filename, overwrite)
@@ -1153,12 +1367,13 @@ def vnfd_create1(ctx, filename, overwrite):
 
     FILENAME: VNFD yaml file or VNFpkg tar.gz file
     """
+    logger.debug("")
     vnfd_create(ctx, filename, overwrite)
 
 
 @cli_osm.command(name='vnfpkg-create', short_help='creates a new VNFD/VNFpkg')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1169,12 +1384,13 @@ def vnfd_create2(ctx, filename, overwrite):
 
     FILENAME: VNFD yaml file or VNFpkg tar.gz file
     """
+    logger.debug("")
     vnfd_create(ctx, filename, overwrite)
 
 
 @cli_osm.command(name='nfpkg-create', short_help='creates a new NFpkg')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1185,6 +1401,7 @@ def nfpkg_create(ctx, filename, overwrite):
 
     FILENAME: NF Descriptor yaml file or NFpkg tar.gz file
     """
+    logger.debug("")
     vnfd_create(ctx, filename, overwrite)
 
 
@@ -1224,6 +1441,7 @@ def ns_create(ctx,
               config_file,
               wait):
     """creates a new NS instance"""
+    logger.debug("")
     # try:
     if config_file:
         check_client_version(ctx.obj, '--config_file')
@@ -1244,6 +1462,7 @@ def ns_create(ctx,
 
 
 def nst_create(ctx, filename, overwrite):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nst.create(filename, overwrite)
@@ -1254,7 +1473,7 @@ def nst_create(ctx, filename, overwrite):
 
 @cli_osm.command(name='nst-create', short_help='creates a new Network Slice Template (NST)')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1265,12 +1484,13 @@ def nst_create1(ctx, filename, overwrite):
 
     FILENAME: NST yaml file or NSTpkg tar.gz file
     """
+    logger.debug("")
     nst_create(ctx, filename, overwrite)
 
 
 @cli_osm.command(name='netslice-template-create', short_help='creates a new Network Slice Template (NST)')
 @click.argument('filename')
-@click.option('--overwrite', 'overwrite', default=None, hidden=True,
+@click.option('--overwrite', 'overwrite', default=None,  # hidden=True,
               help='Deprecated. Use override')
 @click.option('--override', 'overwrite', default=None,
               help='overrides fields in descriptor, format: '
@@ -1281,11 +1501,13 @@ def nst_create2(ctx, filename, overwrite):
 
     FILENAME: NST yaml file or NSTpkg tar.gz file
     """
+    logger.debug("")
     nst_create(ctx, filename, overwrite)
 
 
 def nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
     """creates a new Network Slice Instance (NSI)"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     if config_file:
@@ -1329,6 +1551,7 @@ def nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_fi
 @click.pass_context
 def nsi_create1(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
     """creates a new Network Slice Instance (NSI)"""
+    logger.debug("")
     nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
 
 
@@ -1359,6 +1582,7 @@ def nsi_create1(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_f
 @click.pass_context
 def nsi_create2(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
     """creates a new Network Slice Instance (NSI)"""
+    logger.debug("")
     nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
 
 
@@ -1376,6 +1600,7 @@ def nsi_create2(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_f
 @click.pass_context
 def pdu_create(ctx, name, pdu_type, interface, description, vim_account, descriptor_file):
     """creates a new Physical Deployment Unit (PDU)"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     pdu = {}
@@ -1407,11 +1632,13 @@ def pdu_create(ctx, name, pdu_type, interface, description, vim_account, descrip
     #     print(str(e))
     #     exit(1)
 
+
 ####################
 # UPDATE operations
 ####################
 
 def nsd_update(ctx, name, content):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nsd.update(name, content)
@@ -1430,6 +1657,7 @@ def nsd_update1(ctx, name, content):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nsd_update(ctx, name, content)
 
 
@@ -1443,10 +1671,12 @@ def nsd_update2(ctx, name, content):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nsd_update(ctx, name, content)
 
 
 def vnfd_update(ctx, name, content):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.vnfd.update(name, content)
@@ -1465,6 +1695,7 @@ def vnfd_update1(ctx, name, content):
 
     NAME: name or ID of the VNFD/VNFpkg
     """
+    logger.debug("")
     vnfd_update(ctx, name, content)
 
 
@@ -1478,6 +1709,7 @@ def vnfd_update2(ctx, name, content):
 
     NAME: VNFD yaml file or VNFpkg tar.gz file
     """
+    logger.debug("")
     vnfd_update(ctx, name, content)
 
 
@@ -1491,10 +1723,12 @@ def nfpkg_update(ctx, name, content):
 
     NAME: NF Descriptor yaml file or NFpkg tar.gz file
     """
+    logger.debug("")
     vnfd_update(ctx, name, content)
 
 
 def nst_update(ctx, name, content):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nst.update(name, content)
@@ -1513,6 +1747,7 @@ def nst_update1(ctx, name, content):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nst_update(ctx, name, content)
 
 
@@ -1526,6 +1761,7 @@ def nst_update2(ctx, name, content):
 
     NAME: name or ID of the NSD/NSpkg
     """
+    logger.debug("")
     nst_update(ctx, name, content)
 
 
@@ -1534,6 +1770,7 @@ def nst_update2(ctx, name, content):
 ####################
 
 def nsd_delete(ctx, name, force):
+    logger.debug("")
     # try:
     if not force:
         ctx.obj.nsd.delete(name)
@@ -1554,6 +1791,7 @@ def nsd_delete1(ctx, name, force):
 
     NAME: name or ID of the NSD/NSpkg to be deleted
     """
+    logger.debug("")
     nsd_delete(ctx, name, force)
 
 
@@ -1566,10 +1804,12 @@ def nsd_delete2(ctx, name, force):
 
     NAME: name or ID of the NSD/NSpkg to be deleted
     """
+    logger.debug("")
     nsd_delete(ctx, name, force)
 
 
 def vnfd_delete(ctx, name, force):
+    logger.debug("")
     # try:
     if not force:
         ctx.obj.vnfd.delete(name)
@@ -1590,6 +1830,7 @@ def vnfd_delete1(ctx, name, force):
 
     NAME: name or ID of the VNFD/VNFpkg to be deleted
     """
+    logger.debug("")
     vnfd_delete(ctx, name, force)
 
 
@@ -1602,6 +1843,7 @@ def vnfd_delete2(ctx, name, force):
 
     NAME: name or ID of the VNFD/VNFpkg to be deleted
     """
+    logger.debug("")
     vnfd_delete(ctx, name, force)
 
 
@@ -1614,6 +1856,7 @@ def nfpkg_delete(ctx, name, force):
 
     NAME: name or ID of the NFpkg to be deleted
     """
+    logger.debug("")
     vnfd_delete(ctx, name, force)
 
 
@@ -1632,6 +1875,7 @@ def ns_delete(ctx, name, force, wait):
 
     NAME: name or ID of the NS instance to be deleted
     """
+    logger.debug("")
     # try:
     if not force:
         ctx.obj.ns.delete(name, wait=wait)
@@ -1644,6 +1888,7 @@ def ns_delete(ctx, name, force, wait):
 
 
 def nst_delete(ctx, name, force):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nst.delete(name, force)
@@ -1661,6 +1906,7 @@ def nst_delete1(ctx, name, force):
 
     NAME: name or ID of the NST/NSTpkg to be deleted
     """
+    logger.debug("")
     nst_delete(ctx, name, force)
 
 
@@ -1673,10 +1919,12 @@ def nst_delete2(ctx, name, force):
 
     NAME: name or ID of the NST/NSTpkg to be deleted
     """
+    logger.debug("")
     nst_delete(ctx, name, force)
 
 
 def nsi_delete(ctx, name, force, wait):
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.nsi.delete(name, force, wait=wait)
@@ -1700,6 +1948,7 @@ def nsi_delete1(ctx, name, force, wait):
 
     NAME: name or ID of the Network Slice instance to be deleted
     """
+    logger.debug("")
     nsi_delete(ctx, name, force, wait=wait)
 
 
@@ -1712,6 +1961,7 @@ def nsi_delete2(ctx, name, force, wait):
 
     NAME: name or ID of the Network Slice instance to be deleted
     """
+    logger.debug("")
     nsi_delete(ctx, name, force, wait=wait)
 
 
@@ -1724,6 +1974,7 @@ def pdu_delete(ctx, name, force):
 
     NAME: name or ID of the PDU to be deleted
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.pdu.delete(name, force)
@@ -1785,6 +2036,7 @@ def vim_create(ctx,
                sdn_port_mapping,
                wait):
     """creates a new VIM account"""
+    logger.debug("")
     # try:
     if sdn_controller:
         check_client_version(ctx.obj, '--sdn_controller')
@@ -1843,6 +2095,7 @@ def vim_update(ctx,
 
     NAME: name or ID of the VIM account
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     vim = {}
@@ -1875,6 +2128,7 @@ def vim_delete(ctx, name, force, wait):
 
     NAME: name or ID of the VIM account to be deleted
     """
+    logger.debug("")
     # try:
     if not force:
         ctx.obj.vim.delete(name, wait=wait)
@@ -1895,6 +2149,7 @@ def vim_delete(ctx, name, force, wait):
 @click.pass_context
 def vim_list(ctx, filter):
     """list all VIM accounts"""
+    logger.debug("")
     if filter:
         check_client_version(ctx.obj, '--filter')
 #    if ro_update:
@@ -1919,6 +2174,7 @@ def vim_show(ctx, name):
 
     NAME: name or ID of the VIM account
     """
+    logger.debug("")
     # try:
     resp = ctx.obj.vim.get(name)
     if 'vim_password' in resp:
@@ -1981,6 +2237,7 @@ def wim_create(ctx,
                wim_port_mapping,
                wait):
     """creates a new WIM account"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     # if sdn_controller:
@@ -2034,6 +2291,7 @@ def wim_update(ctx,
 
     NAME: name or ID of the WIM account
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     wim = {}
@@ -2065,6 +2323,7 @@ def wim_delete(ctx, name, force, wait):
 
     NAME: name or ID of the WIM account to be deleted
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.wim.delete(name, force, wait=wait)
@@ -2079,6 +2338,7 @@ def wim_delete(ctx, name, force, wait):
 @click.pass_context
 def wim_list(ctx, filter):
     """list all WIM accounts"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.wim.list(filter)
@@ -2100,6 +2360,7 @@ def wim_show(ctx, name):
 
     NAME: name or ID of the WIM account
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.wim.get(name)
@@ -2127,15 +2388,15 @@ def wim_show(ctx, name):
 @click.option('--type',
               prompt=True,
               help='SDN controller type')
-@click.option('--sdn_controller_version', hidden=True,
+@click.option('--sdn_controller_version',  # hidden=True,
               help='Deprecated. Use --config {version: sdn_controller_version}')
 @click.option('--url',
               help='URL in format http[s]://HOST:IP/')
-@click.option('--ip_address', hidden=True,
+@click.option('--ip_address',  # hidden=True,
               help='Deprecated. Use --url')
-@click.option('--port', hidden=True,
+@click.option('--port',  # hidden=True,
               help='Deprecated. Use --url')
-@click.option('--switch_dpid', hidden=True,
+@click.option('--switch_dpid',  # hidden=True,
               help='Deprecated. Use --config {dpid: DPID}')
 @click.option('--config',
               help='Extra information for SDN in yaml format, as {dpid: (Openflow Datapath ID), version: version}')
@@ -2154,6 +2415,7 @@ def wim_show(ctx, name):
 @click.pass_context
 def sdnc_create(ctx, **kwargs):
     """creates a new SDN controller"""
+    logger.debug("")
     sdncontroller = {x: kwargs[x] for x in kwargs if kwargs[x] and
                      x not in ("wait", "ip_address", "port", "switch_dpid")}
     if kwargs.get("port"):
@@ -2185,10 +2447,10 @@ def sdnc_create(ctx, **kwargs):
                                '{dpid: (Openflow Datapath ID), version: version}')
 @click.option('--user', help='SDN controller username')
 @click.option('--password', help='SDN controller password')
-@click.option('--ip_address', hidden=True, help='Deprecated. Use --url')
-@click.option('--port', hidden=True, help='Deprecated. Use --url')
-@click.option('--switch_dpid', hidden=True, help='Deprecated. Use --config {switch_dpid: DPID}')
-@click.option('--sdn_controller_version', hidden=True, help='Deprecated. Use --config {version: VERSION}')
+@click.option('--ip_address', help='Deprecated. Use --url')  # hidden=True
+@click.option('--port', help='Deprecated. Use --url')  # hidden=True
+@click.option('--switch_dpid', help='Deprecated. Use --config {switch_dpid: DPID}')  # hidden=True
+@click.option('--sdn_controller_version', help='Deprecated. Use --config {version: VERSION}')  # hidden=True
 @click.option('--wait', required=False, default=False, is_flag=True,
               help='do not return the control immediately, but keep it until the operation is completed, or timeout')
 @click.pass_context
@@ -2197,6 +2459,7 @@ def sdnc_update(ctx, **kwargs):
 
     NAME: name or ID of the SDN controller
     """
+    logger.debug("")
     sdncontroller = {x: kwargs[x] for x in kwargs if kwargs[x] and
                      x not in ("wait", "ip_address", "port", "switch_dpid", "new_name")}
     if kwargs.get("newname"):
@@ -2233,6 +2496,7 @@ def sdnc_delete(ctx, name, force, wait):
 
     NAME: name or ID of the SDN controller to be deleted
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.sdnc.delete(name, force, wait=wait)
@@ -2247,6 +2511,7 @@ def sdnc_delete(ctx, name, force, wait):
 @click.pass_context
 def sdnc_list(ctx, filter):
     """list all SDN controllers"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.sdnc.list(filter)
@@ -2268,6 +2533,7 @@ def sdnc_show(ctx, name):
 
     NAME: name or ID of the SDN controller
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.sdnc.get(name)
@@ -2624,6 +2890,7 @@ def project_create(ctx, name):
 
     NAME: name of the project
     """
+    logger.debug("")
     project = {}
     project['name'] = name
     # try:
@@ -2643,6 +2910,7 @@ def project_delete(ctx, name):
 
     NAME: name or ID of the project to be deleted
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.project.delete(name)
@@ -2657,6 +2925,7 @@ def project_delete(ctx, name):
 @click.pass_context
 def project_list(ctx, filter):
     """list all projects"""
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.project.list(filter)
@@ -2678,6 +2947,7 @@ def project_show(ctx, name):
 
     NAME: name or ID of the project
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.project.get(name)
@@ -2708,7 +2978,7 @@ def project_update(ctx, project, name):
     :param name:  new name for the project
     :return:
     """
-
+    logger.debug("")
     project_changes = {}
     project_changes['name'] = name
 
@@ -2748,6 +3018,7 @@ def user_create(ctx, username, password, projects, project_role_mappings):
     PROJECTS: projects assigned to user (internal only)
     PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
     """
+    logger.debug("")
     user = {}
     user['username'] = username
     user['password'] = password
@@ -2798,6 +3069,7 @@ def user_update(ctx, username, password, set_username, set_project, remove_proje
     ADD_PROJECT_ROLE: adding mappings for project/role(s)
     REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
     """
+    logger.debug("")
     user = {}
     user['password'] = password
     user['username'] = set_username
@@ -2824,6 +3096,7 @@ def user_delete(ctx, name):
     \b
     NAME: name or ID of the user to be deleted
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.user.delete(name)
@@ -2859,6 +3132,7 @@ def user_show(ctx, name):
 
     NAME: name or ID of the user
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.user.get(name)
@@ -2902,6 +3176,7 @@ def ns_alarm_create(ctx, name, ns, vnf, vdu, metric, severity,
     """creates a new alarm for a NS instance"""
     # TODO: Check how to validate threshold_value.
     # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
+    logger.debug("")
     # try:
     ns_instance = ctx.obj.ns.get(ns)
     alarm = {}
@@ -2958,6 +3233,7 @@ def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
     """exports a metric to the internal OSM bus, which can be read by other apps"""
     # TODO: Check how to validate interval.
     # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
+    logger.debug("")
     # try:
     ns_instance = ctx.obj.ns.get(ns)
     metric_data = {}
@@ -3005,6 +3281,7 @@ def upload_package(ctx, filename):
 
     FILENAME: VNF or NS package file (tar.gz)
     """
+    logger.debug("")
     # try:
     ctx.obj.package.upload(filename)
     fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
@@ -3194,6 +3471,7 @@ def ns_action(ctx,
 
     NS_NAME: name or ID of the NS instance
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     op_data = {}
@@ -3240,6 +3518,7 @@ def vnf_scale(ctx,
     NS_NAME: name or ID of the NS instance.
     VNF_NAME: member-vnf-index in the NS to be scaled.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     if not scale_in and not scale_out:
@@ -3268,6 +3547,7 @@ def role_create(ctx, name, permissions):
     NAME: Name or ID of the role.
     DEFINITION: Definition of grant/denial of access to resources.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.role.create(name, permissions)
@@ -3301,6 +3581,7 @@ def role_update(ctx, name, set_name, add, remove):
     ADD: Grant/denial of access to resource to add.
     REMOVE: Grant/denial of access to resource to remove.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.role.update(name, set_name, None, add, remove)
@@ -3320,6 +3601,7 @@ def role_delete(ctx, name):
     \b
     NAME: Name or ID of the role.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     ctx.obj.role.delete(name)
@@ -3336,6 +3618,7 @@ def role_list(ctx, filter):
     """
     List all roles.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.role.list(filter)
@@ -3359,6 +3642,7 @@ def role_show(ctx, name):
     \b
     NAME: Name or ID of the role.
     """
+    logger.debug("")
     # try:
     check_client_version(ctx.obj, ctx.command.name)
     resp = ctx.obj.role.get(name)
@@ -3521,16 +3805,21 @@ def package_build(ctx,
 def cli():
     try:
         cli_osm()
+        exit(0)
     except pycurl.error as exc:
         print(exc)
         print('Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified')
-        exit(1)
     except ClientException as exc:
         print("ERROR: {}".format(exc))
-        exit(1)
+    except (FileNotFoundError, PermissionError) as exc:
+        print("Cannot open file: {}".format(exc))
+    except yaml.YAMLError as exc:
+        print("Invalid YAML format: {}".format(exc))
+    exit(1)
     # TODO capture other controlled exceptions here
     # TODO remove the ClientException captures from all places, unless they do something different
 
 
 if __name__ == '__main__':
     cli()
+