diff --git a/docs/source/guides/admin-guides/references/man1/rinv.1.rst b/docs/source/guides/admin-guides/references/man1/rinv.1.rst index d760fc576..4f28900ab 100644 --- a/docs/source/guides/admin-guides/references/man1/rinv.1.rst +++ b/docs/source/guides/admin-guides/references/man1/rinv.1.rst @@ -39,7 +39,7 @@ OpenPOWER (OpenBMC) server specific: ==================================== -\ **rinv**\ \ *noderange*\ [\ **model | serial | firm | cpu | dimm | all**\ ] [\ **-V | -**\ **-verbose**\ ] +\ **rinv**\ \ *noderange*\ [\ **model**\ ][\ **serial**\ ][\ **firm**\ ][\ **cpu**\ ][\ **dimm**\ ][\ **all**\ ] [\ **-V | -**\ **-verbose**\ ] PPC (with HMC) specific: diff --git a/perl-xCAT/xCAT/Usage.pm b/perl-xCAT/xCAT/Usage.pm index 608f8db77..4f36bea66 100755 --- a/perl-xCAT/xCAT/Usage.pm +++ b/perl-xCAT/xCAT/Usage.pm @@ -136,7 +136,7 @@ my %usage = ( ", "rinv.openbmc" => "OpenPOWER (OpenBMC) server specific: - rinv [model|serial|firm|cpu|dimm|all] [-V|--verbose] + rinv [model][serial][firm][cpu][dimm][all] [-V|--verbose] ", "rinv.end" => "PPC specific(with HMC): diff --git a/xCAT-client/pods/man1/rinv.1.pod b/xCAT-client/pods/man1/rinv.1.pod index 52ed22ccc..661f067f5 100644 --- a/xCAT-client/pods/man1/rinv.1.pod +++ b/xCAT-client/pods/man1/rinv.1.pod @@ -16,7 +16,7 @@ B I [B|B|B|B|B|B|B I [B|B|B|B|B|B] [B<-V>|B<--verbose>] +B I [B][B][B][B][B][B] [B<-V>|B<--verbose>] =head2 PPC (with HMC) specific: diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py index aa863951b..3061a4814 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py @@ -74,18 +74,47 @@ class OpenBMCInventoryTask(ParallelNodesCommand): return firm_info - def get_info(self, inventory_type, **kw): + def get_info(self, inventory_types, **kw): node = kw['node'] obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, debugmode=self.debugmode, verbose=self.verbose) inventory_info = [] + + # inventory_types contains an array of different inventories to get + # Go through the array and set flags to optimize invnetory calls + model_or_serial = 0 + cpu_or_dimm = 0 + all = 0 + inventory_type = 'all' + for type in inventory_types: + if type == 'model' or type == 'serial': + # For model and serial we can make a single call + model_or_serial = 1 + if type == 'cpu' or type == 'dimm': + # For cpu and dimm we can make a single call + cpu_or_dimm = 1 + if type == 'all': + all = 1 + if all == 1: + inventory_type = 'all' + elif model_or_serial == 1 and cpu_or_dimm == 1: + # Both model_or_serial and cpu_or_dimm were set, might as well ask for all + inventory_type = 'all' + elif model_or_serial == 1: + inventory_type = 'model' + elif cpu_or_dimm == 1: + inventory_type = 'cpu' + try: obmc.login() + # Extract the data from the BMC inventory_info_dict = obmc.get_inventory_info(inventory_type) - if inventory_type == 'all' or not inventory_type: + # Process returned inventory_info_dict depending on the inventory requested + if all == 1: + # Everything gets displayed, even firmware keys = inventory_info_dict.keys() keys.sort() for key in keys: @@ -95,17 +124,28 @@ class OpenBMCInventoryTask(ParallelNodesCommand): firm_info = self._get_firm_info(firm_dict_list) inventory_info += firm_info - elif inventory_type == 'model' or inventory_type == 'serial': - key = 'Model' if inventory_type == 'model' else 'SerialNumber' - if 'SYSTEM' in inventory_info_dict: - for system_info in inventory_info_dict['SYSTEM']: - if key in system_info: - inventory_info = [system_info] - break else: - key = inventory_type.upper() - if key in inventory_info_dict: - inventory_info = utils.sort_string_with_numbers(inventory_info_dict[key]) + if model_or_serial == 1: + # Model or serial was requested + for one_inventory_type in inventory_types: + if one_inventory_type == 'model': + key = 'Model' + elif one_inventory_type == 'serial': + key = 'SerialNumber' + else: + continue + + if 'SYSTEM' in inventory_info_dict: + for system_info in inventory_info_dict['SYSTEM']: + if key in system_info: + inventory_info += [system_info] + break + if cpu_or_dimm: + # cpu or dimm was requested + for one_inventory_type in inventory_types: + key = one_inventory_type.upper() + if key in inventory_info_dict: + inventory_info += utils.sort_string_with_numbers(inventory_info_dict[key]) if not inventory_info: inventory_info = ['No attributes returned from the BMC.'] diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py b/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py index 9709f1659..041c29b93 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py @@ -10,10 +10,10 @@ class InventoryInterface(object): interface_type = 'inventory' version = '1.0' - def get_inventory_info(self, task, inventory_type=None): + def get_inventory_info(self, task, inventory_type=[]): """Return the inventory info of the task's nodes. - :param inventory_type: type of inventory info want to get. + :param inventory_type: array of type of inventory info want to get. :param task: a Task instance containing the nodes to act on. :return inventory info list """ diff --git a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py index 850e0b8b2..c6a64288f 100644 --- a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py +++ b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py @@ -223,9 +223,16 @@ class OpenBMCManager(base.BaseManager): if not args or (len(args) == 1 and args[0] in ['-V', '--verbose']): args.append('all') + # We are not using a standard Python options (with - or --) because + # of that, we need to specify multiple identical choices. If only + # one optional choice is specified - [all|cpu|dimm|firm|model|serial] + # only one option at a time is allowed. + # If specified - [all][cpu][dimm][firm][model][serial], then multiple + # options are accepted, but they are required to be ordered, + # e.g "cpu dimm" will work, but not "dimm cpu" rinv_usage = """ Usage: - rinv [-V|--verbose] [all|cpu|dimm|firm|model|serial] + rinv [-V|--verbose] [all|cpu|dimm|firm|model|serial] [all|cpu|dimm|firm|model|serial] [all|cpu|dimm|firm|model|serial] [all|cpu|dimm|firm|model|serial] [all|cpu|dimm|firm|model|serial] Options: -V --verbose rinv verbose mode. @@ -235,22 +242,37 @@ class OpenBMCManager(base.BaseManager): opts = docopt(rinv_usage, argv=args) self.verbose = opts.pop('--verbose') - action = [k for k,v in opts.items() if v][0] + actions = [k for k,v in opts.items() if v] except Exception as e: self.messager.error("Failed to parse arguments for rinv: %s" % args) return # 2, validate the args - if action not in INVENTORY_OPTIONS: - self.messager.error("Not supported subcommand for rinv: %s" % action) - return + run_firmware_inventory = 0 + run_other_inventory = 0 + for action in actions: + # Check if each action is valid + if action not in INVENTORY_OPTIONS: + self.messager.error("Not supported subcommand for rinv: %s" % action) + return + else: + # Valid action, set flags for which calls to make later + if action == 'all': + run_firmware_inventory = 0 + run_other_inventory = 1 + break # get all inventory, nothing else matters + elif action == 'firm': + run_firmware_inventory = 1 + else: + run_other_inventory = 1 # 3, run the subcommands runner = OpenBMCInventoryTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose) - if action == 'firm': + if run_firmware_inventory == 1: DefaultInventoryManager().get_firm_info(runner) - else: - DefaultInventoryManager().get_inventory_info(runner, action) + actions.remove('firm') # Remove element from actions array + if run_other_inventory == 1: + DefaultInventoryManager().get_inventory_info(runner, actions) def rpower(self, nodesinfo, args): diff --git a/xCAT-server/lib/xcat/plugins/openbmc2.pm b/xCAT-server/lib/xcat/plugins/openbmc2.pm index 4525c0acb..cae8d1363 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc2.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc2.pm @@ -183,7 +183,7 @@ sub parse_args { return ([ 1, "Error parsing arguments." ]); } - if (scalar(@ARGV) >= 2 and ($command =~ /rbeacon|rinv|rpower|rvitals/)) { + if (scalar(@ARGV) >= 2 and ($command =~ /rbeacon|rpower|rvitals/)) { return ([ 1, "Only one option is supported at the same time for $command" ]); } elsif (scalar(@ARGV) == 0 and $command =~ /rbeacon|rspconfig|rpower|rflash/) { return ([ 1, "No option specified for $command" ]); @@ -244,9 +244,18 @@ sub parse_args { return ([ 1, "Invalid option specified with '-l|--list'."]) if (@ARGV); } } elsif ($command eq "rinv") { - $subcommand = "all" if (!defined($ARGV[0])); - unless ($subcommand =~ /^all$|^cpu$|^dimm$|^firm$|^model$|^serial$/) { - return ([ 1, "Unsupported command: $command $subcommand" ]); + if (!defined($ARGV[0])) { + $subcommand = "all"; + } else { + foreach my $each_subcommand (@ARGV) { + # Check if each passed subcommand is valid + if ($each_subcommand =~ /^all$|^cpu$|^dimm$|^firm$|^model$|^serial$/) { + $subcommand .= $each_subcommand . " "; + } else { + # Exit once we find an invalid subcommand + return ([ 1, "Unsupported command: $command $each_subcommand" ]); + } + } } } elsif ($command eq "rpower") { unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {