""" This module containts all the entry points for the redfish cli tools. It uses argparse to add subparses. All of this is developed and tested against Dell iDRACs at the moment. At some point in its future there will be a lot of refactoring to deal with other OEMs I expect. """ import json import logging import sys # PYTHON_ARGCOMPLETE_OK import argcomplete from redfish_cli import api from redfish_cli.api import storage import redfish_cli.cli.jobs from .parsers import parse_args from .utils import error, table, write_output def chassis(args): """Entry point: get the list of chassis""" details = api.chassis(args.server, args.username, args.password) write_output(details, output_format=args.format) def chassis_details(args): """Entry point: get the details of a chassis""" details = api.chassis_details( args.server, args.username, args.password, args.chassis ) write_output(details, output_format=args.format) def create_logical_volume(args): """Stub for the create logical volume command""" try: result = storage.create_logical_volume(args) write_output(result) except api.exceptions.InvalidRaidLevel as exc: error(exc.msg) except api.exceptions.LogicalVolumeCreationFailure as exc: error(json.dumps(exc.json, indent=2)) def delete_logical_volume(args): """Delete a logical volume""" logging.debug(args) try: result = api.storage.delete_logical_volume(args) write_output( result, output_format=args.format, ) # except api.exceptions.FailedToGetJobID as exc: # details = exc.msg # error_msg = ( # "An error has occured. The usual cause is that the disk " # f"specified ({args.disk}) does not exist\n" # f"{details}" # ) # error(error_msg) except api.exceptions.ResponseNotOK as exc: details = exc.response.text error_msg = ( "An error has occured. The usual cause is that the disk " f"specified ({args.disk}) does not exist\n" f"{details}" ) error(error_msg) def configure_logging(args): """Configure logging for the cli""" log_format = ( "%(asctime)s - %(pathname)s:%(funcName)s - %(levelname)s - %(message)s" ) logging.basicConfig( filename="redfish.log", level=getattr(logging, args.log_level.upper()), format=log_format, ) def get(args): """ Write the results of an arbitrary get on the specified url to stdout (using print). Currently it always dumps the results as json, but it should respect the the output format in the args. It will also just exit with an error message if a url requires authentication and no username and password is supplied. This could be handled better. """ url = args.url if url is None: url = "" if args.expand: url += "?$expand=.($levels=1)" try: result = api.utils.get( args.server, url, username=args.username, password=args.password, ) write_output( result, output_format=args.format, ) except api.exceptions.Unauthorized: error("This url requires authentication\n") except api.exceptions.ResponseNotOK as exc: error(json.dumps(json.loads(exc.response.text), indent=2)) def logical_volume(args): """ Entry point: get the details of a logical volume. By default the first logical drive in the first storage controller of the first system. """ logging.debug( "server: %s username: %s system: %s controller: %s drive: %s", args.server, args.username, args.system, args.controller, args.drive, ) try: write_output( storage.logical_volume_details(args), output_format=args.format, ) except api.exceptions.ResponseNotOK as exc: error(json.dumps(json.loads(exc.response.text), indent=2)) def logical_volumes(args): """ Entry point: get the list of logical volumes attached to a storage controller (which in turn is part of a system) """ try: result = storage.list_logical_volumes(args) write_output( result, output_format=args.format, ) except api.exceptions.ResponseNotOK as exc: error(json.dumps(json.loads(exc.response.text), indent=2)) def physical_volume(args): """ Entry point: get the list of physical volumes attached to a storage controller (which in turn is part of a system) """ data = storage.physical_volume(args) # if args.format == "text": # result = "\n".join([ f"{x['system']} {x['drive']}" for x in data]) # elif args.format == "json": # result = data # elif args.format == "table": # if args.verbose: # table = [ [x['system'], x['drive'], x['url']] for x in data] # headers=["System", "Drive", "URL"] # else: # table = [ [x['system'], x['drive']] for x in data] # headers=["System", "Drive"] # result = tabulate(table, headers=headers, tablefmt="outline") result = data write_output(result, output_format=args.format) def physical_volumes(args): """ Entry point: get the list of physical volumes attached to a storage controller (which in turn is part of a system) """ data = storage.list_physical_volumes(args) if args.format == "text": result = "\n".join([f"{x['system']} {x['drive']}" for x in data]) elif args.format == "json": result = data elif args.format == "table": if args.verbose: data = [[x["system"], x["drive"], x["url"]] for x in data] headers = ["System", "Drive", "URL"] else: data = [[x["system"], x["drive"]] for x in data] headers = ["System", "Drive"] result = table(data, headers=headers) write_output(result, output_format=args.format) def product(args): """Entry point: get the product name of a server""" details = api.product(args.server) write_output(details, output_format=args.format) def redfish(args=None): """ Entrypoint: Base command, gets args from stdin unless they are passed in as a parameter (which probably means we are being called from a test) """ if args is None: args = parse_args(sys.argv[1:]) if args.debug: args.log_level = "DEBUG" configure_logging(args) if "func" in args: args.func(args) else: write_output(api.utils.get(args.server, ""), output_format=args.format) def service_tag(args): """Entry point: get the service tag of a Dell server""" try: write_output(api.service_tag(args.server), output_format=args.format) except api.exceptions.DellOnly: error("Service tags are only available for Dell iDRACs") def storage_controller(args): """Entry point: get the details of a storage controllers in a server""" try: result = storage.storage_controller_details(args) write_output( result, output_format=args.format, ) except api.exceptions.ResponseNotOK as exc: error(json.dumps(json.loads(exc.response.text), indent=2)) def storage_controllers(args): """Entry point: get the list of storage controllers in a server""" result = storage.list_storage_controllers(args) if not args.verbose: controller_list = [] for i in result["Members"]: controller_list.append(i["@odata.id"].split("/")[-1]) result = controller_list if args.format == "text": result = "\n".join(result) elif args.format == "table": data = [] for row in result: data.append([row]) result = table(data, headers=["Controller"]) write_output( result, output_format=args.format, ) def system_details(args): """Entry point: get the details of a system in a server""" details = api.power.system_details( args.server, args.username, args.password, args.system ) write_output(details, output_format=args.format) def version(args): """Entry point: get the verion of redfish implemented by the BMC""" redfish_version = api.redfish_version(args.server) write_output(redfish_version, output_format=args.format)