Initial commit
This commit is contained in:
commit
1b51716d1b
72 changed files with 8204 additions and 0 deletions
308
src/redfish_cli/cli/__init__.py
Normal file
308
src/redfish_cli/cli/__init__.py
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
"""
|
||||
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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue