text: #!/usr/bin/python
  #
  # Copyright: Ansible Project
  # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
  
  from __future__ import absolute_import, division, print_function
  __metaclass__ = type
  
  DOCUMENTATION = '''
  ---
  module: onyx_facts
  author: "Waleed Mousa (@waleedym), Samer Deeb (@samerd)"
  short_description: Collect facts from Mellanox ONYX network devices
  description:
    - Collects a base set of device facts from a ONYX Mellanox network devices
      This module prepends all of the base network fact keys with
      C(ansible_net_<fact>).  The facts module will always collect a base set of
      facts from the device and can enable or disable collection of additional
      facts.
  notes:
    - Tested against ONYX 3.6
  options:
    gather_subset:
      description:
        - When supplied, this argument will restrict the facts collected
          to a given subset.  Possible values for this argument include
          all, version, module, and interfaces.  Can specify a list of
          values to include a larger subset.  Values can also be used
          with an initial C(M(!)) to specify that a specific subset should
          not be collected.
      required: false
      default: version
  '''
  
  EXAMPLES = """
  ---
  - name: Collect all facts from the device
    onyx_facts:
      gather_subset: all
  - name: Collect only the interfaces facts
    onyx_facts:
      gather_subset:
        - interfaces
  - name: Do not collect version facts
    onyx_facts:
      gather_subset:
        - "!version"
  """
  
  RETURN = """
  ansible_net_gather_subset:
    description: The list of fact subsets collected from the device
    returned: always
    type: list
  # version
  ansible_net_version:
    description: A hash of all currently running system image information
    returned: when version is configured or when no gather_subset is provided
    type: dict
  # modules
  ansible_net_modules:
    description: A hash of all modules on the systeme with status
    returned: when modules is configured
    type: dict
  # interfaces
  ansible_net_interfaces:
    description: A hash of all interfaces running on the system
    returned: when interfaces is configured
    type: dict
  """
  
  from ansible.module_utils.basic import AnsibleModule
  from ansible.module_utils.six import iteritems
  
  from ansible_collections.mellanox.onyx.plugins.module_utils.network.onyx.onyx import BaseOnyxModule
  from ansible_collections.mellanox.onyx.plugins.module_utils.network.onyx.onyx import show_cmd
  
  
  class OnyxFactsModule(BaseOnyxModule):
  
      def get_runable_subset(self, gather_subset):
          runable_subsets = set()
          exclude_subsets = set()
          for subset in gather_subset:
              if subset == 'all':
                  runable_subsets.update(VALID_SUBSETS)
                  continue
  
              if subset.startswith('!'):
                  subset = subset[1:]
                  if subset == 'all':
                      exclude_subsets.update(VALID_SUBSETS)
                      continue
                  exclude = True
              else:
                  exclude = False
  
              if subset not in VALID_SUBSETS:
                  self._module.fail_json(msg='Bad subset')
  
              if exclude:
                  exclude_subsets.add(subset)
              else:
                  runable_subsets.add(subset)
  
          if not runable_subsets:
              runable_subsets.update(VALID_SUBSETS)
  
          runable_subsets.difference_update(exclude_subsets)
          if not runable_subsets:
              runable_subsets.add('version')
          return runable_subsets
  
      def init_module(self):
          """ module initialization
          """
          argument_spec = dict(
              gather_subset=dict(default=['version'], type='list')
          )
          self._module = AnsibleModule(
              argument_spec=argument_spec,
              supports_check_mode=True)
  
      def run(self):
          self.init_module()
          gather_subset = self._module.params['gather_subset']
          runable_subsets = self.get_runable_subset(gather_subset)
          facts = dict()
          facts['gather_subset'] = list(runable_subsets)
  
          instances = list()
          for key in runable_subsets:
              facter_cls = FACT_SUBSETS[key]
              instances.append(facter_cls(self._module))
  
          for inst in instances:
              inst.populate()
              facts.update(inst.facts)
  
          ansible_facts = dict()
          for key, value in iteritems(facts):
              key = 'ansible_net_%s' % key
              ansible_facts[key] = value
          self._module.exit_json(ansible_facts=ansible_facts)
  
  
  class FactsBase(object):
  
      COMMANDS = ['']
  
      def __init__(self, module):
          self.module = module
          self.facts = dict()
          self.responses = None
  
      def _show_cmd(self, cmd):
          return show_cmd(self.module, cmd, json_fmt=True)
  
      def populate(self):
          self.responses = []
          for cmd in self.COMMANDS:
              self.responses.append(self._show_cmd(cmd))
  
  
  class Version(FactsBase):
  
      COMMANDS = ['show version']
  
      def populate(self):
          super(Version, self).populate()
          data = self.responses[0]
          if data:
              self.facts['version'] = data
  
  
  class Module(FactsBase):
  
      COMMANDS = ['show module']
  
      def populate(self):
          super(Module, self).populate()
          data = self.responses[0]
          if data:
              self.facts['modules'] = data
  
  
  class Interfaces(FactsBase):
  
      COMMANDS = ['show version', 'show interfaces ethernet']
  
      def populate(self):
          super(Interfaces, self).populate()
  
          version_data = self.responses[0]
          os_version = version_data['Product release']
          data = self.responses[1]
  
          if data:
              self.facts['interfaces'] = self.populate_interfaces(data, os_version)
  
      def extractIfData(self, interface_data):
          return {"MAC Address": interface_data["Mac address"],
                  "Actual Speed": interface_data["Actual speed"],
                  "MTU": interface_data["MTU"],
                  "Admin State": interface_data["Admin state"],
                  "Operational State": interface_data["Operational state"]}
  
      def populate_interfaces(self, interfaces, os_version):
          interfaces_dict = dict()
          for if_data in interfaces:
              if_dict = dict()
              if os_version >= BaseOnyxModule.ONYX_API_VERSION:
                  for if_name, interface_data in iteritems(if_data):
                      interface_data = interface_data[0]
                      if_dict = self.extractIfData(interface_data)
                      if_name = if_dict["Interface Name"] = if_name
  
              else:
                  if_dict = self.extractIfData(if_data)
                  if_name = if_dict["Interface Name"] = if_data["header"]
              interfaces_dict[if_name] = if_dict
          return interfaces_dict
  
  
  FACT_SUBSETS = dict(
      version=Version,
      modules=Module,
      interfaces=Interfaces
  )
  
  VALID_SUBSETS = frozenset(FACT_SUBSETS.keys())
  
  
  def main():
      """ main entry point for module execution
      """
      OnyxFactsModule.main()
  
  
  if __name__ == '__main__':
      main()
  