diff --git a/ci/roles/baremetal_inspect/defaults/main.yml b/ci/roles/baremetal_inspect/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d993fcdb787b2d65658c7e9e70fbf810ff614f49
--- /dev/null
+++ b/ci/roles/baremetal_inspect/defaults/main.yml
@@ -0,0 +1,56 @@
+expected_fields:
+  - allocation_id
+  - bios_interface
+  - boot_interface
+  - boot_mode
+  - chassis_id
+  - clean_step
+  - conductor
+  - conductor_group
+  - console_interface
+  - created_at
+  - deploy_interface
+  - deploy_step
+  - driver
+  - driver_info
+  - driver_internal_info
+  - extra
+  - fault
+  - id
+  - inspect_interface
+  - instance_id
+  - instance_info
+  - is_automated_clean_enabled
+  - is_console_enabled
+  - is_maintenance
+  - is_protected
+  - is_retired
+  - is_secure_boot
+  - last_error
+  - links
+  - maintenance_reason
+  - management_interface
+  - name
+  - network_interface
+  - owner
+  - port_groups
+  - ports
+  - power_interface
+  - power_state
+  - properties
+  - protected_reason
+  - provision_state
+  - raid_config
+  - raid_interface
+  - rescue_interface
+  - reservation
+  - resource_class
+  - retired_reason
+  - states
+  - storage_interface
+  - target_power_state
+  - target_provision_state
+  - target_raid_config
+  - traits
+  - updated_at
+  - vendor_interface
diff --git a/ci/roles/baremetal_inspect/tasks/main.yml b/ci/roles/baremetal_inspect/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..63860c994e38018cce321aad7c4ace22ab27d5ae
--- /dev/null
+++ b/ci/roles/baremetal_inspect/tasks/main.yml
@@ -0,0 +1,15 @@
+---
+# TODO: Actually run this role in CI. Atm we do not have DevStack's ironic plugin enabled.
+- name: Introspect node
+  openstack.cloud.baremetal_inspect:
+    cloud: "{{ cloud }}"
+    name: node-1
+  register: inspect
+
+- debug: var=inspect
+
+- name: assert return values of baremetal_inspect module
+  assert:
+    that:
+      # allow new fields to be introduced but prevent fields from being removed
+      - expected_fields|difference(inspect.node.keys())|length == 0
diff --git a/plugins/modules/baremetal_inspect.py b/plugins/modules/baremetal_inspect.py
index 0692f7ba121038dd8ee66a1a1aa20d31eb7e3b10..d77ee8376ab4846627d47f17a40ffc8260225d01 100644
--- a/plugins/modules/baremetal_inspect.py
+++ b/plugins/modules/baremetal_inspect.py
@@ -10,32 +10,21 @@ module: baremetal_inspect
 short_description: Explicitly triggers baremetal node introspection in ironic.
 author: OpenStack Ansible SIG
 description:
-    - Requests Ironic to set a node into inspect state in order to collect metadata regarding the node.
-      This command may be out of band or in-band depending on the ironic driver configuration.
-      This is only possible on nodes in 'manageable' and 'available' state.
+    - Requests Ironic to set a node into inspect state in order to collect
+      metadata regarding the node. This command may be out of band or in-band
+      depending on the ironic driver configuration. This is only possible on
+      nodes in 'manageable' and 'available' state.
 options:
     mac:
       description:
         - unique mac address that is used to attempt to identify the host.
       type: str
-    uuid:
-      description:
-        - globally unique identifier (UUID) to identify the host.
-      type: str
     name:
       description:
-        - unique name identifier to identify the host in Ironic.
-      type: str
-    ironic_url:
-      description:
-        - If noauth mode is utilized, this is required to be set to the endpoint URL for the Ironic API.
-          Use with "auth" and "auth_type" settings set to None.
+        - Name or id of the node to inspect.
+        - Mutually exclusive with I(mac)
       type: str
-    timeout:
-      description:
-        - A timeout in seconds to tell the role to wait for the node to complete introspection if wait is set to True.
-      default: 1200
-      type: int
+      aliases: [id, uuid]
 
 requirements:
     - "python >= 3.6"
@@ -46,27 +35,260 @@ extends_documentation_fragment:
 '''
 
 RETURN = '''
-ansible_facts:
-    description: Dictionary of new facts representing discovered properties of the node..
-    returned: changed
-    type: complex
-    contains:
+node:
+  description: A dictionary describing the node after inspection
+  returned: changed
+  type: dict
+  contains:
+    allocation_id:
+      description: The UUID of the allocation associated with the node.
+      type: str
+    bios_interface:
+      description: The bios interface to be used for this node.
+      type: str
+    boot_interface:
+      description: The boot interface for a Node, e.g. "pxe".
+      type: str
+    boot_mode:
+      description: The current boot mode state (uefi/bios).
+      type: str
+    chassis_id:
+      description: UUID of the chassis associated with this Node.
+      type: str
+    clean_step:
+      description: |
+        The current clean step. Introduced with the cleaning feature.
+      type: str
+    conductor:
+      description: The conductor currently servicing a node.
+      type: str
+    conductor_group:
+      description: The conductor group for a node.
+      type: str
+    console_interface:
+      description: Console interface to use when working with serial console.
+      type: str
+      sample: no-console
+    created_at:
+      description: Timestamp at which the node was last updated.
+      type: str
+    deploy_interface:
+      description: The deploy interface for a node
+      type: str
+      sample: iscsi
+    deploy_step:
+      description: The current deploy step.
+      type: str
+    driver:
+      description: The name of the driver.
+      type: str
+    driver_info:
+      description: |
+        All the metadata required by the driver to manage this Node. List
+        of fields varies between drivers.
+      type: dict
+    driver_internal_info:
+      description: Internal metadata set and stored by the Node's driver.
+      type: dict
+    extra:
+      description: A set of one or more arbitrary metadata key and value pairs.
+      type: dict
+    fault:
+      description: |
+        The fault indicates the active fault detected by ironic, typically the
+        Node is in "maintenance mode". None means no fault has been detected by
+        ironic. "power failure" indicates ironic failed to retrieve power state
+        from this node. There are other possible types, e.g., "clean failure"
+        and "rescue abort failure".
+      type: str
+    id:
+      description: The UUID for the resource.
+      type: str
+    inspect_interface:
+      description: The interface used for node inspection.
+      type: str
+      sample: no-inspect
+    instance_id:
+      description: UUID of the Nova instance associated with this Node.
+      type: str
+    instance_info:
+      description: |
+        Information used to customize the deployed image. May include root
+        partition size, a base 64 encoded config drive, and other metadata.
+        Note that this field is erased automatically when the instance is
+        deleted (this is done by requesting the Node provision state be changed
+        to DELETED).
+      type: dict
+    is_automated_clean_enabled:
+      description: Override enabling of automated cleaning.
+      type: bool
+    is_console_enabled:
+      description: |
+        Indicates whether console access is enabled or disabled on this node.
+      type: bool
+    is_maintenance:
+      description: |
+        Whether or not this Node is currently in "maintenance mode". Setting
+        a Node into maintenance mode removes it from the available resource
+        pool and halts some internal automation. This can happen manually (eg,
+        via an API request) or automatically when Ironic detects a hardware
+        fault that prevents communication with the machine.
+      type: bool
+    is_protected:
+      description: |
+        Whether the node is protected from undeploying, rebuilding and
+        deletion.
+      type: bool
+    is_retired:
+      description: Whether the node is marked for retirement.
+      type: bool
+    is_secure_boot:
+      description: |
+        Whether the node is currently booted with secure boot turned on.
+      type: bool
+    last_error:
+      description: |
+        Any error from the most recent (last) transaction that started but
+        failed to finish.
+      type: str
+    links:
+      description: |
+        A list of relative links. Includes the self and bookmark links.
+      type: list
+    maintenance_reason:
+      description: |
+        User-settable description of the reason why this Node was placed into
+        maintenance mode.
+      type: str
+    management_interface:
+      description: Interface for out-of-band node management.
+      type: str
+      sample: ipmitool
+    name:
+      description: |
+        Human-readable identifier for the Node resource. Certain words are
+        reserved.
+      type: str
+    network_interface:
+      description: |
+        Which Network Interface provider to use when plumbing the network
+        connections for this Node.
+      type: str
+    owner:
+      description: A string or UUID of the tenant who owns the object.
+      type: str
+    port_groups:
+      description: Links to the collection of portgroups on this node.
+      type: list
+    ports:
+      description: Links to the collection of ports on this node
+      type: list
+    power_interface:
+      description: Interface used for performing power actions on the node.
+      type: str
+      sample: ipmitool
+    power_state:
+      description: |
+        The current power state of this Node. Usually, "power on" or "power
+        off", but may be "None" if Ironic is unable to determine the power
+        state (eg, due to hardware failure).
+      type: str
+    properties:
+      description: Properties of the node as found by inspection
+      type: dict
+      contains:
         memory_mb:
-            description: Amount of node memory as updated in the node properties
-            type: str
-            sample: "1024"
+          description: Amount of node memory as updated in the node properties
+          type: str
+          sample: "1024"
         cpu_arch:
-            description: Detected CPU architecture type
-            type: str
-            sample: "x86_64"
+          description: Detected CPU architecture type
+          type: str
+          sample: "x86_64"
         local_gb:
-            description: Total size of local disk storage as updated in node properties.
-            type: str
-            sample: "10"
+          description: |
+            Total size of local disk storage as updated in node properties.
+          type: str
+          sample: "10"
         cpus:
-            description: Count of cpu cores defined in the updated node properties.
-            type: str
-            sample: "1"
+          description: |
+            Count of cpu cores defined in the updated node properties.
+          type: str
+          sample: "1"
+    protected_reason:
+      description: The reason the node is marked as protected.
+      type: str
+    provision_state:
+      description: The current provisioning state of this Node.
+      type: str
+    raid_config:
+      description: |
+        Represents the current RAID configuration of the node. Introduced with
+        the cleaning feature.
+      type: dict
+    raid_interface:
+      description: Interface used for configuring RAID on this node.
+      type: str
+      sample: no-raid
+    rescue_interface:
+      description: The interface used for node rescue.
+      type: str
+      sample: no-rescue
+    reservation:
+      description: |
+        The name of an Ironic Conductor host which is holding a lock on this
+        node, if a lock is held. Usually "null", but this field can be useful
+        for debugging.
+      type: str
+    resource_class:
+      description: |
+        A string which can be used by external schedulers to identify this
+        Node as a unit of a specific type of resource.
+      type: str
+    retired_reason:
+      description: TODO
+      type: str
+    states:
+      description: |
+        Links to the collection of states. Note that this resource is also
+        used to request state transitions.
+      type: list
+    storage_interface:
+      description: |
+        Interface used for attaching and detaching volumes on this node, e.g.
+        "cinder".
+      type: str
+    target_power_state:
+      description: |
+        If a power state transition has been requested, this field represents
+        the requested (ie, "target") state, either "power on" or "power off".
+      type: str
+    target_provision_state:
+      description: |
+        If a provisioning action has been requested, this field represents
+        the requested (ie, "target") state. Note that a Node may go through
+        several states during its transition to this target state. For
+        instance, when requesting an instance be deployed to an AVAILABLE
+        Node, the Node may go through the following state change progression:
+        AVAILABLE -> DEPLOYING -> DEPLOYWAIT -> DEPLOYING -> ACTIVE.
+      type: str
+    target_raid_config:
+      description: |
+        Represents the requested RAID configuration of the node, which will
+        be applied when the Node next transitions through the CLEANING state.
+        Introduced with the cleaning feature.
+      type: dict
+    traits:
+      description: List of traits for this node.
+      type: list
+    updated_at:
+      description: TODO
+      type: str
+    vendor_interface:
+      description: |
+        Interface for vendor-specific functionality on this node, e.g.
+        "no-vendor".
+      type: str
 '''
 
 EXAMPLES = '''
@@ -75,58 +297,50 @@ EXAMPLES = '''
     name: "testnode1"
 '''
 
-from ansible_collections.openstack.cloud.plugins.module_utils.ironic import (
-    IronicModule,
-    ironic_argument_spec,
-)
 from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
-    openstack_module_kwargs,
-    openstack_cloud_from_module
+    OpenStackModule
 )
 
 
-def _choose_id_value(module):
-    if module.params['uuid']:
-        return module.params['uuid']
-    if module.params['name']:
-        return module.params['name']
-    return None
-
-
-def main():
-    argument_spec = ironic_argument_spec(
-        uuid=dict(),
-        name=dict(),
+class BaremetalInspectModule(OpenStackModule):
+    argument_spec = dict(
+        name=dict(aliases=['uuid', 'id']),
         mac=dict(),
-        timeout=dict(default=1200, type='int'),
     )
-    module_kwargs = openstack_module_kwargs()
-    module = IronicModule(argument_spec, **module_kwargs)
-
-    sdk, cloud = openstack_cloud_from_module(module)
-    try:
-        if module.params['name'] or module.params['uuid']:
-            server = cloud.get_machine(_choose_id_value(module))
-        elif module.params['mac']:
-            server = cloud.get_machine_by_mac(module.params['mac'])
-        else:
-            module.fail_json(msg="The worlds did not align, "
-                                 "the host was not found as "
-                                 "no name, uuid, or mac was "
-                                 "defined.")
-        if server:
-            cloud.inspect_machine(server['uuid'], module.params['wait'])
-            # TODO(TheJulia): diff properties, ?and ports? and determine
-            # if a change occurred.  In theory, the node is always changed
-            # if introspection is able to update the record.
-            module.exit_json(changed=True,
-                             ansible_facts=server['properties'])
 
+    module_kwargs = dict(
+        mutually_exclusive=[
+            ('name', 'mac'),
+        ],
+        required_one_of=[
+            ('name', 'mac'),
+        ],
+    )
+
+    def run(self):
+        node_name_or_id = self.params['name']
+        node = None
+        if node_name_or_id is not None:
+            node = self.conn.baremetal.find_node(node_name_or_id)
         else:
-            module.fail_json(msg="node not found.")
+            node = self.conn.get_machine_by_mac(self.params['mac'])
+
+        if node is None:
+            self.fail_json(msg="node not found.")
 
-    except sdk.exceptions.OpenStackCloudException as e:
-        module.fail_json(msg=str(e))
+        node = self.conn.inspect_machine(node['id'],
+                                         wait=self.params['wait'],
+                                         timeout=self.params['timeout'])
+        node = node.to_dict(computed=False)
+        # TODO(TheJulia): diff properties, ?and ports? and determine
+        # if a change occurred.  In theory, the node is always changed
+        # if introspection is able to update the record.
+        self.exit_json(changed=True, node=node)
+
+
+def main():
+    module = BaremetalInspectModule()
+    module()
 
 
 if __name__ == "__main__":