iLO-manager first main commitgit status
This commit is contained in:
1 parent
e6f4cc04ca
commit
599d8da562
3271 files changed
+550655
No files matched your search
@@ -0,0 +1,424 @@
|
||||
###
|
||||
# Copyright 2016-2021 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
###
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Save Command for RDMC"""
|
||||
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
|
||||
import redfish.ris
|
||||
|
||||
try:
|
||||
from rdmc_helper import (
|
||||
Encryption,
|
||||
InvalidCommandLineError,
|
||||
InvalidCommandLineErrorOPTS,
|
||||
InvalidFileFormattingError,
|
||||
ReturnCodes,
|
||||
iLORisCorruptionError,
|
||||
)
|
||||
except ImportError:
|
||||
from ilorest.rdmc_helper import (
|
||||
Encryption,
|
||||
InvalidCommandLineError,
|
||||
InvalidCommandLineErrorOPTS,
|
||||
InvalidFileFormattingError,
|
||||
ReturnCodes,
|
||||
iLORisCorruptionError,
|
||||
)
|
||||
|
||||
# default file name
|
||||
__filename__ = "ilorest.json"
|
||||
|
||||
|
||||
class SaveCommand:
|
||||
"""Constructor"""
|
||||
|
||||
def __init__(self):
|
||||
self.ident = {
|
||||
"name": "save",
|
||||
"usage": None,
|
||||
"description": "Run to save a selected type to a file"
|
||||
"\n\texample: save --selector HpBios.\n\n\tChange the default "
|
||||
"output filename\n\texample: save --selector HpBios. -f "
|
||||
"output.json\n\n\tTo save multiple types in one file\n\texample: "
|
||||
"save --multisave Bios.,ComputerSystem.",
|
||||
"summary": "Saves the selected type's settings to a file.",
|
||||
"aliases": [],
|
||||
"auxcommands": ["SelectCommand"],
|
||||
}
|
||||
self.filename = __filename__
|
||||
self.cmdbase = None
|
||||
self.rdmc = None
|
||||
self.auxcommands = dict()
|
||||
|
||||
def run(self, line, help_disp=False):
|
||||
"""Main save worker function
|
||||
|
||||
:param line: command line input
|
||||
:type line: string.
|
||||
"""
|
||||
if help_disp:
|
||||
self.parser.print_help()
|
||||
return ReturnCodes.SUCCESS
|
||||
try:
|
||||
(options, args) = self.rdmc.rdmc_parse_arglist(self, line)
|
||||
except (InvalidCommandLineErrorOPTS, SystemExit):
|
||||
if ("-h" in line) or ("--help" in line):
|
||||
return ReturnCodes.SUCCESS
|
||||
else:
|
||||
raise InvalidCommandLineErrorOPTS("")
|
||||
|
||||
if options.multisave:
|
||||
options.selector = ""
|
||||
if (
|
||||
hasattr(options, "selector")
|
||||
and options.selector is not None
|
||||
and "hpbaseconfigs" not in options.selector.lower()
|
||||
and "hpebaseconfigs" not in options.selector.lower()
|
||||
and "bios" not in options.selector.lower()
|
||||
):
|
||||
self.savevalidation(options)
|
||||
else:
|
||||
# filename validations and checks
|
||||
self.cmdbase.login_validation(self, options)
|
||||
self.filename = None
|
||||
if options.filename and len(options.filename) > 1:
|
||||
raise InvalidCommandLineError("Save command doesn't support multiple filenames.")
|
||||
elif options.filename:
|
||||
self.filename = options.filename[0]
|
||||
elif self.rdmc.config:
|
||||
if self.rdmc.config.defaultsavefilename:
|
||||
self.filename = self.rdmc.config.defaultsavefilename
|
||||
|
||||
if not self.filename:
|
||||
self.filename = __filename__
|
||||
|
||||
# if args:
|
||||
# raise InvalidCommandLineError("Save command takes no arguments.")
|
||||
|
||||
self.rdmc.ui.printer("Saving configuration...\n")
|
||||
if options.filter:
|
||||
try:
|
||||
if (str(options.filter)[0] == str(options.filter)[-1]) and str(options.filter).startswith(("'", '"')):
|
||||
options.filter = options.filter[1:-1]
|
||||
|
||||
(sel, val) = options.filter.split("=")
|
||||
sel = sel.strip()
|
||||
val = val.strip()
|
||||
except:
|
||||
raise InvalidCommandLineError("Invalid filter" " parameter format [filter_attribute]=[filter_value]")
|
||||
|
||||
instances = self.rdmc.app.select(
|
||||
selector=self.rdmc.app.selector,
|
||||
fltrvals=(sel, val),
|
||||
path_refresh=True,
|
||||
)
|
||||
contents = self.saveworkerfunction(options, instances=instances)
|
||||
else:
|
||||
contents = self.saveworkerfunction(options)
|
||||
|
||||
if options.multisave:
|
||||
for select in options.multisave:
|
||||
try:
|
||||
self.auxcommands["select"].run(select)
|
||||
except:
|
||||
pass
|
||||
contents += self.saveworkerfunction(options)
|
||||
|
||||
if not contents:
|
||||
raise redfish.ris.NothingSelectedError
|
||||
else:
|
||||
# TODO: Maybe add this to the command. Not sure we use it elsewhere in the lib
|
||||
contents = self.add_save_file_header(contents)
|
||||
|
||||
if options.encryption:
|
||||
with open(self.filename, "wb") as outfile:
|
||||
outfile.write(
|
||||
Encryption().encrypt_file(
|
||||
json.dumps(contents, indent=2, cls=redfish.ris.JSONEncoder),
|
||||
options.encryption,
|
||||
)
|
||||
)
|
||||
else:
|
||||
with open(self.filename, "w") as outfile:
|
||||
outfile.write(json.dumps(contents, indent=2, cls=redfish.ris.JSONEncoder, sort_keys=True))
|
||||
self.rdmc.ui.printer("Configuration saved to: %s\n" % self.filename)
|
||||
|
||||
self.cmdbase.logout_routine(self, options)
|
||||
|
||||
# Return code
|
||||
return ReturnCodes.SUCCESS
|
||||
|
||||
def saveworkerfunction(self, options, instances=None):
|
||||
"""Returns the currently selected type for saving
|
||||
|
||||
:param instances: list of instances from select to save
|
||||
:type instances: list.
|
||||
"""
|
||||
try:
|
||||
if (
|
||||
options.selector is not None
|
||||
and (
|
||||
"bios" in options.selector.lower()
|
||||
or "hpbaseconfigs" in options.selector.lower()
|
||||
or "hpebaseconfigs" in options.selector.lower()
|
||||
)
|
||||
) and (options.multisave is None or options.multisave == ""):
|
||||
raise KeyError
|
||||
content = self.rdmc.app.getprops(insts=instances)
|
||||
try:
|
||||
contents = [{val[self.rdmc.app.typepath.defs.hrefstring]: val} for val in content]
|
||||
except KeyError:
|
||||
try:
|
||||
contents = [{val["links"]["self"][self.rdmc.app.typepath.defs.hrefstring]: val} for val in content]
|
||||
except KeyError:
|
||||
raise iLORisCorruptionError(
|
||||
"iLO Database seems to be corrupted. Please check. Reboot the server to " "restore\n"
|
||||
)
|
||||
except Exception:
|
||||
config_path = None
|
||||
contents = list()
|
||||
if options.selector is not None:
|
||||
if options.selector.lower() == "bios." or "bios.v" in options.selector.lower():
|
||||
config_path = ["/redfish/v1/systems/1/bios/settings/"]
|
||||
elif options.selector.lower() == "bios":
|
||||
config_path = [
|
||||
"/redfish/v1/systems/1/bios/settings/",
|
||||
"/redfish/v1/systems/1/bios/mappings/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/mappings/",
|
||||
]
|
||||
elif "hpbaseconfigs" in options.selector.lower() or "hpebaseconfigs" in options.selector.lower():
|
||||
config_path = [
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/nvmeof/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/iscsi/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/tlsconfig/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/serverconfiglock/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/kmsconfig/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/boot/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/nvmeof/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/iscsi/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/tlsconfig/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/serverconfiglock/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/kmsconfig/baseconfigs/",
|
||||
"/redfish/v1/systems/1/bios/boot/baseconfigs/",
|
||||
]
|
||||
elif "hpebiosmapping" in options.selector.lower():
|
||||
config_path = [
|
||||
"/redfish/v1/systems/1/bios/mappings",
|
||||
"/redfish/v1/systems/1/bios/oem/hpe/mappings/",
|
||||
]
|
||||
result = None
|
||||
for b in config_path:
|
||||
try:
|
||||
result = self.rdmc.app.get_handler(b, silent=True, service=True)
|
||||
except:
|
||||
pass
|
||||
if result is not None:
|
||||
if result.status == 200:
|
||||
d = {b: result.dict}
|
||||
contents.append(d)
|
||||
|
||||
type_string = self.rdmc.app.typepath.defs.typestring
|
||||
|
||||
templist = list()
|
||||
srnum_list = list()
|
||||
|
||||
for content in contents:
|
||||
typeselector = None
|
||||
pathselector = None
|
||||
|
||||
for path, values in content.items():
|
||||
# if "Managers/1/EthernetInterfaces/1" not in path:
|
||||
for dictentry in list(values.keys()):
|
||||
if dictentry == type_string:
|
||||
typeselector = values[dictentry]
|
||||
pathselector = path
|
||||
del values[dictentry]
|
||||
if dictentry in [
|
||||
"IPv4Addresses",
|
||||
"IPv6Addresses",
|
||||
"IPv6AddressPolicyTable",
|
||||
"MACAddress",
|
||||
"StaticNameServers",
|
||||
# "AutoNeg",
|
||||
# "FullDuplex",
|
||||
"SpeedMbps",
|
||||
]:
|
||||
del values[dictentry]
|
||||
if dictentry in [
|
||||
"IPv6StaticAddresses",
|
||||
"IPv6StaticDefaultGateways",
|
||||
"IPv4StaticAddresses",
|
||||
]:
|
||||
if values[dictentry]:
|
||||
del values[dictentry]
|
||||
if dictentry in ["IPv4", "IPv6", "DHCPv6", "DHCPv4"]:
|
||||
if "DNSServers" in values[dictentry]:
|
||||
del values[dictentry]["DNSServers"]
|
||||
del values["Oem"]["Hpe"][dictentry]["DNSServers"]
|
||||
if "UseDNSServers" in values[dictentry]:
|
||||
del values[dictentry]["UseDNSServers"]
|
||||
del values["Oem"]["Hpe"][dictentry]["UseDNSServers"]
|
||||
|
||||
if values:
|
||||
skip = False
|
||||
if "SerialNumber" in values and values["SerialNumber"] is not None and values["SerialNumber"] != "":
|
||||
if values["SerialNumber"] in srnum_list:
|
||||
skip = True
|
||||
else:
|
||||
srnum_list.append(values["SerialNumber"])
|
||||
tempcontents = dict()
|
||||
|
||||
if not skip:
|
||||
if typeselector and pathselector:
|
||||
tempcontents[typeselector] = {pathselector: values}
|
||||
else:
|
||||
raise InvalidFileFormattingError("Missing path or selector in input file.")
|
||||
|
||||
templist.append(tempcontents)
|
||||
|
||||
return templist
|
||||
|
||||
def nested_sort(self, data):
|
||||
"""Helper function to sort all dictionary key:value pairs
|
||||
|
||||
:param data: dictionary to sort
|
||||
:type data: dict.
|
||||
"""
|
||||
|
||||
for key, value in data.items():
|
||||
if isinstance(value, dict):
|
||||
data[key] = self.nested_sort(value)
|
||||
|
||||
data = OrderedDict(sorted(list(data.items()), key=lambda x: x[0]))
|
||||
|
||||
return data
|
||||
|
||||
def savevalidation(self, options):
|
||||
"""Save method validation function
|
||||
|
||||
:param options: command line options
|
||||
:type options: list.
|
||||
"""
|
||||
|
||||
if options.multisave:
|
||||
options.multisave = options.multisave.replace('"', "").replace("'", "")
|
||||
options.multisave = options.multisave.replace(" ", "").split(",")
|
||||
if not len(options.multisave) >= 1:
|
||||
raise InvalidCommandLineError("Invalid number of types in multisave option.")
|
||||
options.selector = options.multisave[0]
|
||||
options.multisave = options.multisave[1:]
|
||||
|
||||
self.cmdbase.login_select_validation(self, options)
|
||||
|
||||
# filename validations and checks
|
||||
self.filename = None
|
||||
|
||||
if options.filename and len(options.filename) > 1:
|
||||
raise InvalidCommandLineError("Save command doesn't support multiple filenames.")
|
||||
elif options.filename:
|
||||
self.filename = options.filename[0]
|
||||
elif self.rdmc.config:
|
||||
if self.rdmc.config.defaultsavefilename:
|
||||
self.filename = self.rdmc.config.defaultsavefilename
|
||||
|
||||
if not self.filename:
|
||||
self.filename = __filename__
|
||||
|
||||
def add_save_file_header(self, contents):
|
||||
"""Helper function to retrieve the comments for save file
|
||||
|
||||
:param contents: current save contents
|
||||
:type contents: list.
|
||||
"""
|
||||
templist = list()
|
||||
|
||||
headers = self.rdmc.app.create_save_header()
|
||||
templist.append(headers)
|
||||
|
||||
for content in contents:
|
||||
templist.append(content)
|
||||
|
||||
return templist
|
||||
|
||||
def definearguments(self, customparser):
|
||||
"""Wrapper function for new command main function
|
||||
|
||||
:param customparser: command line input
|
||||
:type customparser: parser.
|
||||
"""
|
||||
if not customparser:
|
||||
return
|
||||
|
||||
self.cmdbase.add_login_arguments_group(customparser)
|
||||
customparser.add_argument(
|
||||
"-f",
|
||||
"--filename",
|
||||
dest="filename",
|
||||
help="Use this flag if you wish to use a different filename than the default one. "
|
||||
"The default filename is %s." % __filename__,
|
||||
action="append",
|
||||
default=None,
|
||||
)
|
||||
|
||||
customparser.add_argument(
|
||||
"--selector",
|
||||
dest="selector",
|
||||
help="Optionally include this flag to select a type to run the current command on. "
|
||||
"Use this flag when you wish to select a type without entering another command, "
|
||||
"or if you wish to work with a type that is different from the one currently "
|
||||
"selected.",
|
||||
default=None,
|
||||
# required=True,
|
||||
)
|
||||
customparser.add_argument(
|
||||
"--multisave",
|
||||
dest="multisave",
|
||||
help="Optionally include this flag to save multiple types to a single file. "
|
||||
"Overrides the currently selected type.\n\t Usage: --multisave type1.,type2.,type3.",
|
||||
default="",
|
||||
)
|
||||
customparser.add_argument(
|
||||
"--filter",
|
||||
dest="filter",
|
||||
help="Optionally set a filter value for a filter attribute. This uses the provided "
|
||||
"filter for the currently selected type. Note: Use this flag to narrow down your "
|
||||
"results. For example, selecting a common type might return multiple objects that "
|
||||
"are all of that type. If you want to modify the properties of only one of those "
|
||||
"objects, use the filter flag to narrow down results based on properties."
|
||||
"\n\t Usage: --filter [ATTRIBUTE]=[VALUE]",
|
||||
default=None,
|
||||
)
|
||||
customparser.add_argument(
|
||||
"-j",
|
||||
"--json",
|
||||
dest="json",
|
||||
action="store_true",
|
||||
help="Optionally include this flag if you wish to change the displayed output to "
|
||||
"JSON format. Preserving the JSON data structure makes the information easier to "
|
||||
"parse.",
|
||||
default=False,
|
||||
)
|
||||
customparser.add_argument(
|
||||
"--encryption",
|
||||
dest="encryption",
|
||||
help="Optionally include this flag to encrypt/decrypt a file using the key provided.",
|
||||
default=None,
|
||||
)
|
||||
Reference in new issue
Block a user