Repository: metal3-io/baremetal-operator
Pull request #1355 (2023-09-13 08:24:44)

⚠️ Use ironic inventory API instead of calling ironic-inspector
Removes the direct dependency on ironic-inspector, leaving it an implementation detail of Ironic.

Note for reviewers: it's much easier to review each of 3 commits separately.

metal3-io-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please ask for approval from dtantsur. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=metal3-io%2Fbaremetal-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/metal3-io/baremetal-operator/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["dtantsur"]} -->
dtantsur: /test-ubuntu-integration-main 
metal3-io-bot: @dtantsur: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
gomod | 8a880c84d7026fe449f49f23f3b0ba68adceef77 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/gomod/1701874552310599680) | true | `/test gomod`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1355). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:dtantsur).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @dtantsur: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
gomod | 8a880c84d7026fe449f49f23f3b0ba68adceef77 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/gomod/1701874552310599680) | true | `/test gomod`
unit | 8a880c84d7026fe449f49f23f3b0ba68adceef77 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/unit/1701874552369319936) | true | `/test unit`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1355). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:dtantsur).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @dtantsur: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
unit | a84273bcff220af6c795febf051952ceaef4ee48 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/unit/1701875653386702848) | true | `/test unit`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1355). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:dtantsur).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
dtantsur: /test-ubuntu-integration-main
metal3-io-bot: @dtantsur: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
unit | c6482d461376c5870202beb93e4cc37a1fbd0073 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/unit/1701949645841764352) | true | `/test unit`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1355). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:dtantsur).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
dtantsur: /test-ubuntu-integration-main
metal3-io-bot: @dtantsur: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
unit | 6525397fc900b0a1537922263e8f4a81f0d940dd | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1355/unit/1702010294160592896) | true | `/test unit`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1355). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:dtantsur).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
dtantsur: /test-ubuntu-integration-main

Patch:
diff --git a/cmd/get-hardware-details/main.go b/cmd/get-hardware-details/main.go
index 5f824a63..c06dc7fc 100644
--- a/cmd/get-hardware-details/main.go
+++ b/cmd/get-hardware-details/main.go
@@ -5,10 +5,13 @@ package main
 import (
 	"encoding/json"
 	"fmt"
+	"net"
+	"net/url"
 	"os"
 	"strings"
 
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
+	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
+	"k8s.io/klog/v2"
 
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/hardwaredetails"
@@ -34,22 +37,38 @@ func main() {
 		InsecureSkipVerify: ironicInsecure,
 	}
 
-	inspector, err := clients.InspectorClient(opts.Endpoint, opts.AuthConfig, tlsConf)
+	endpoint := opts.Endpoint
+	parsedEndpoint, err := url.Parse(endpoint)
 	if err != nil {
-		fmt.Printf("could not get inspector client: %s", err)
+		fmt.Printf("invalid ironic endpoint: %s", err)
 		os.Exit(1)
 	}
 
-	introData := introspection.GetIntrospectionData(inspector, opts.NodeID)
+	// Previously, this command accepted the Inspector endpoint. But since
+	// we're transitioning to not using Inspector directly, it now requires
+	// the Ironic endpoint. Try to handle the transition by checking for
+	// the well-known Inspector port and replacing it with the Ironic port.
+	if parsedEndpoint.Port() == "5050" {
+		parsedEndpoint.Host = net.JoinHostPort(parsedEndpoint.Hostname(), "6385")
+		endpoint = parsedEndpoint.String()
+	}
+
+	ironic, err := clients.IronicClient(endpoint, opts.AuthConfig, tlsConf)
+	if err != nil {
+		fmt.Printf("could not get ironic client: %s", err)
+		os.Exit(1)
+	}
+
+	introData := nodes.GetInventory(ironic, opts.NodeID)
 	data, err := introData.Extract()
 	if err != nil {
-		fmt.Printf("could not get introspection data: %s", err)
+		fmt.Printf("could not get inspection data: %s", err)
 		os.Exit(1)
 	}
 
-	json, err := json.MarshalIndent(hardwaredetails.GetHardwareDetails(data), "", "\t")
+	json, err := json.MarshalIndent(hardwaredetails.GetHardwareDetails(data, klog.NewKlogr()), "", "\t")
 	if err != nil {
-		fmt.Printf("could not convert introspection data: %s", err)
+		fmt.Printf("could not convert inspection data: %s", err)
 		os.Exit(1)
 	}
 
@@ -58,7 +77,7 @@ func main() {
 
 func getOptions() (o options) {
 	if len(os.Args) != 3 {
-		fmt.Println("Usage: get-hardware-details <inspector URI> <node UUID>")
+		fmt.Println("Usage: get-hardware-details <ironic URI> <node UUID>")
 		os.Exit(1)
 	}
 
diff --git a/docs/configuration.md b/docs/configuration.md
index 00d33057..b5f88179 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -70,4 +70,4 @@ When an external Ironic is used, the following requirements must be met:
 * Either HTTP basic or no-auth authentication must be used (Keystone is not
   supported).
 
-* API version 1.74 (Xena release cycle) or newer must be available.
+* API version 1.81 (2023.1 "Antelope" release cycle) or newer must be available.
diff --git a/go.mod b/go.mod
index 59dd2d35..667531f7 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.20
 require (
 	github.com/go-logr/logr v1.2.4
 	github.com/google/safetext v0.0.0-20230106111101-7156a760e523
-	github.com/gophercloud/gophercloud v1.6.0
+	github.com/gophercloud/gophercloud v1.5.1-0.20230912084133-c79ed6d3b371
 	github.com/metal3-io/baremetal-operator/apis v0.2.0
 	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.2.0
 	github.com/onsi/gomega v1.27.10
@@ -62,7 +62,7 @@ require (
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
 	golang.org/x/net v0.14.0 // indirect
 	golang.org/x/oauth2 v0.5.0 // indirect
-	golang.org/x/sys v0.11.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
 	golang.org/x/term v0.11.0 // indirect
 	golang.org/x/text v0.12.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index ceb0d0b1..5c5b10d7 100644
--- a/go.sum
+++ b/go.sum
@@ -72,8 +72,8 @@ github.com/google/safetext v0.0.0-20230106111101-7156a760e523 h1:i4NsbmB9pD5+Ggp
 github.com/google/safetext v0.0.0-20230106111101-7156a760e523/go.mod h1:mJNEy0r5YPHC7ChQffpOszlGB4L1iqjXWpIEKcFpr9s=
 github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
 github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gophercloud/gophercloud v1.6.0 h1:JwJN1bauRnWPba5ueWs9IluONHteXPWjjK+MvfM4krY=
-github.com/gophercloud/gophercloud v1.6.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
+github.com/gophercloud/gophercloud v1.5.1-0.20230912084133-c79ed6d3b371 h1:/4TDrmUM3o52/9J3Pn4mZ3VP7CYiFkDKRNuWyxLkpp4=
+github.com/gophercloud/gophercloud v1.5.1-0.20230912084133-c79ed6d3b371/go.mod h1:vYRGjRkTeMAwdvQFTVuPGfRWv4dc3J2QHy9H3bHD6Pc=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
@@ -156,7 +156,6 @@ go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
@@ -177,7 +176,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -196,19 +194,16 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
-golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
 golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
diff --git a/pkg/provisioner/ironic/clients/auth.go b/pkg/provisioner/ironic/clients/auth.go
index 443487d5..fe9e7370 100644
--- a/pkg/provisioner/ironic/clients/auth.go
+++ b/pkg/provisioner/ironic/clients/auth.go
@@ -39,8 +39,9 @@ func readAuthFile(filename string) (string, error) {
 	return strings.TrimSpace(string(content)), err
 }
 
-func load(clientType string) (auth AuthConfig, err error) {
-	authPath := path.Join(authRoot(), clientType)
+// LoadAuth loads the Ironic configuration from the environment
+func LoadAuth() (auth AuthConfig, err error) {
+	authPath := path.Join(authRoot(), "ironic")
 
 	if _, err := os.Stat(authPath); err != nil {
 		if os.IsNotExist(err) {
@@ -69,16 +70,6 @@ func load(clientType string) (auth AuthConfig, err error) {
 	return
 }
 
-// LoadAuth loads the Ironic and Inspector configuration from the environment
-func LoadAuth() (ironicAuth, inspectorAuth AuthConfig, err error) {
-	ironicAuth, err = load("ironic")
-	if err != nil {
-		return
-	}
-	inspectorAuth, err = load("ironic-inspector")
-	return
-}
-
 // ConfigFromEndpointURL returns an endpoint and an auth config from an
 // endpoint URL that may contain HTTP basic auth credentials.
 func ConfigFromEndpointURL(endpointURL string) (endpoint string, auth AuthConfig, err error) {
diff --git a/pkg/provisioner/ironic/clients/client.go b/pkg/provisioner/ironic/clients/client.go
index cb4f836f..ad2821ed 100644
--- a/pkg/provisioner/ironic/clients/client.go
+++ b/pkg/provisioner/ironic/clients/client.go
@@ -9,8 +9,6 @@ import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/httpbasic"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/noauth"
-	httpbasicintrospection "github.com/gophercloud/gophercloud/openstack/baremetalintrospection/httpbasic"
-	noauthintrospection "github.com/gophercloud/gophercloud/openstack/baremetalintrospection/noauth"
 	"go.etcd.io/etcd/client/pkg/v3/transport"
 )
 
@@ -95,31 +93,8 @@ func IronicClient(ironicEndpoint string, auth AuthConfig, tls TLSConfig) (client
 
 	// Ensure we have a microversion high enough to get the features
 	// we need. Update docs/configuration.md when updating the version.
-	// Version 1.74 allows retrival of the BIOS Registry
-	client.Microversion = "1.74"
+	// Version 1.81 allows retrival of Node inventory
+	client.Microversion = "1.81"
 
 	return updateHTTPClient(client, tls)
 }
-
-// InspectorClient creates a client for Ironic Inspector
-func InspectorClient(inspectorEndpoint string, auth AuthConfig, tls TLSConfig) (client *gophercloud.ServiceClient, err error) {
-	switch auth.Type {
-	case NoAuth:
-		client, err = noauthintrospection.NewBareMetalIntrospectionNoAuth(
-			noauthintrospection.EndpointOpts{
-				IronicInspectorEndpoint: inspectorEndpoint,
-			})
-	case HTTPBasicAuth:
-		client, err = httpbasicintrospection.NewBareMetalIntrospectionHTTPBasic(httpbasicintrospection.EndpointOpts{
-			IronicInspectorEndpoint:     inspectorEndpoint,
-			IronicInspectorUser:         auth.Username,
-			IronicInspectorUserPassword: auth.Password,
-		})
-	default:
-		err = fmt.Errorf("Unknown auth type %s", auth.Type)
-	}
-	if err != nil {
-		return
-	}
-	return updateHTTPClient(client, tls)
-}
diff --git a/pkg/provisioner/ironic/dependencies.go b/pkg/provisioner/ironic/dependencies.go
index 92549258..06d3662f 100644
--- a/pkg/provisioner/ironic/dependencies.go
+++ b/pkg/provisioner/ironic/dependencies.go
@@ -15,26 +15,22 @@ const (
 )
 
 type ironicDependenciesChecker struct {
-	client    *gophercloud.ServiceClient
-	inspector *gophercloud.ServiceClient
-	log       logr.Logger
+	client *gophercloud.ServiceClient
+	log    logr.Logger
 }
 
-func newIronicDependenciesChecker(client *gophercloud.ServiceClient, inspector *gophercloud.ServiceClient, log logr.Logger) *ironicDependenciesChecker {
+func newIronicDependenciesChecker(client *gophercloud.ServiceClient, log logr.Logger) *ironicDependenciesChecker {
 	return &ironicDependenciesChecker{
-		client:    client,
-		inspector: inspector,
-		log:       log,
+		client: client,
+		log:    log,
 	}
 }
 
 func (i *ironicDependenciesChecker) IsReady() (result bool, err error) {
-
-	ready, err := i.checkIronic()
-	if ready && err == nil {
-		ready = i.checkIronicInspector()
+	ready := i.checkEndpoint(i.client)
+	if ready {
+		ready, err = i.checkIronicConductor()
 	}
-
 	return ready, err
 }
 
@@ -53,14 +49,6 @@ func (i *ironicDependenciesChecker) checkEndpoint(client *gophercloud.ServiceCli
 	return err == nil
 }
 
-func (i *ironicDependenciesChecker) checkIronic() (ready bool, err error) {
-	ready = i.checkEndpoint(i.client)
-	if ready {
-		ready, err = i.checkIronicConductor()
-	}
-	return ready, err
-}
-
 func (i *ironicDependenciesChecker) checkIronicConductor() (ready bool, err error) {
 
 	pager := drivers.ListDrivers(i.client, drivers.ListDriversOpts{
@@ -86,7 +74,3 @@ func (i *ironicDependenciesChecker) checkIronicConductor() (ready bool, err erro
 
 	return ready, err
 }
-
-func (i *ironicDependenciesChecker) checkIronicInspector() (ready bool) {
-	return i.checkEndpoint(i.inspector)
-}
diff --git a/pkg/provisioner/ironic/factory.go b/pkg/provisioner/ironic/factory.go
index d70f2b49..4a2a140e 100644
--- a/pkg/provisioner/ironic/factory.go
+++ b/pkg/provisioner/ironic/factory.go
@@ -19,11 +19,9 @@ type ironicProvisionerFactory struct {
 	log    logr.Logger
 	config ironicConfig
 
-	// Keep pointers to ironic and inspector clients configured with
-	// the global auth settings to reuse the connection between
-	// reconcilers.
-	clientIronic    *gophercloud.ServiceClient
-	clientInspector *gophercloud.ServiceClient
+	// Keep pointers to ironic client configured with the global
+	// auth settings to reuse the connection between reconcilers.
+	clientIronic *gophercloud.ServiceClient
 }
 
 func NewProvisionerFactory(logger logr.Logger, havePreprovImgBuilder bool) provisioner.Factory {
@@ -40,7 +38,7 @@ func NewProvisionerFactory(logger logr.Logger, havePreprovImgBuilder bool) provi
 }
 
 func (f *ironicProvisionerFactory) init(havePreprovImgBuilder bool) error {
-	ironicAuth, inspectorAuth, err := clients.LoadAuth()
+	ironicAuth, err := clients.LoadAuth()
 	if err != nil {
 		return err
 	}
@@ -50,7 +48,7 @@ func (f *ironicProvisionerFactory) init(havePreprovImgBuilder bool) error {
 		return err
 	}
 
-	ironicEndpoint, inspectorEndpoint, err := loadEndpointsFromEnv()
+	ironicEndpoint, err := loadEndpointsFromEnv()
 	if err != nil {
 		return err
 	}
@@ -60,8 +58,6 @@ func (f *ironicProvisionerFactory) init(havePreprovImgBuilder bool) error {
 	f.log.Info("ironic settings",
 		"endpoint", ironicEndpoint,
 		"ironicAuthType", ironicAuth.Type,
-		"inspectorEndpoint", inspectorEndpoint,
-		"inspectorAuthType", inspectorAuth.Type,
 		"deployKernelURL", f.config.deployKernelURL,
 		"deployRamdiskURL", f.config.deployRamdiskURL,
 		"deployISOURL", f.config.deployISOURL,
@@ -79,12 +75,6 @@ func (f *ironicProvisionerFactory) init(havePreprovImgBuilder bool) error {
 		return err
 	}
 
-	f.clientInspector, err = clients.InspectorClient(
-		inspectorEndpoint, inspectorAuth, tlsConf)
-	if err != nil {
-		return err
-	}
-
 	return nil
 }
 
@@ -100,7 +90,6 @@ func (f ironicProvisionerFactory) ironicProvisioner(hostData provisioner.HostDat
 		disableCertVerification: hostData.DisableCertificateVerification,
 		bootMACAddress:          hostData.BootMACAddress,
 		client:                  f.clientIronic,
-		inspector:               f.clientInspector,
 		log:                     provisionerLogger,
 		debugLog:                provisionerLogger.V(1),
 		publisher:               publisher,
@@ -167,16 +156,11 @@ func loadConfigFromEnv(havePreprovImgBuilder bool) (ironicConfig, error) {
 	return c, nil
 }
 
-func loadEndpointsFromEnv() (ironicEndpoint, inspectorEndpoint string, err error) {
+func loadEndpointsFromEnv() (ironicEndpoint string, err error) {
 	ironicEndpoint = os.Getenv("IRONIC_ENDPOINT")
 	if ironicEndpoint == "" {
 		err = errors.New("No IRONIC_ENDPOINT variable set")
 	}
-	inspectorEndpoint = os.Getenv("IRONIC_INSPECTOR_ENDPOINT")
-	if inspectorEndpoint == "" {
-		err = errors.New("No IRONIC_INSPECTOR_ENDPOINT variable set")
-	}
-
 	return
 }
 
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
index 6c312889..3ee904b2 100644
--- a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
+++ b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
@@ -6,18 +6,26 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/go-logr/logr"
+	"github.com/gophercloud/gophercloud/openstack/baremetal/inventory"
+	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 
 	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 )
 
 // GetHardwareDetails converts Ironic introspection data into BareMetalHost HardwareDetails.
-func GetHardwareDetails(data *introspection.Data) *metal3api.HardwareDetails {
+func GetHardwareDetails(data *nodes.InventoryData, logger logr.Logger) *metal3api.HardwareDetails {
+	inspectorData, err := data.PluginData.AsInspectorData()
+	if err != nil {
+		logger.Error(err, "cannot get plugin data from inventory, some fields will not be available")
+	}
+
 	details := new(metal3api.HardwareDetails)
 	details.Firmware = getFirmwareDetails(data.Inventory.SystemVendor.Firmware)
 	details.SystemVendor = getSystemVendorDetails(data.Inventory.SystemVendor)
-	details.RAMMebibytes = data.MemoryMB
-	details.NIC = getNICDetails(data.Inventory.Interfaces, data.AllInterfaces)
+	details.RAMMebibytes = data.Inventory.Memory.PhysicalMb
+	details.NIC = getNICDetails(data.Inventory.Interfaces, inspectorData.AllInterfaces)
 	details.Storage = getStorageDetails(data.Inventory.Disks)
 	details.CPU = getCPUDetails(&data.Inventory.CPU)
 	details.Hostname = data.Inventory.Hostname
@@ -47,7 +55,7 @@ func getVLANs(intf introspection.BaseInterfaceType) (vlans []metal3api.VLAN, vla
 	return
 }
 
-func getNICDetails(ifdata []introspection.InterfaceType,
+func getNICDetails(ifdata []inventory.InterfaceType,
 	basedata map[string]introspection.BaseInterfaceType) []metal3api.NIC {
 	var nics []metal3api.NIC
 	for _, intf := range ifdata {
@@ -85,7 +93,7 @@ func getNICDetails(ifdata []introspection.InterfaceType,
 	return nics
 }
 
-func getDiskType(diskdata introspection.RootDiskType) metal3api.DiskType {
+func getDiskType(diskdata inventory.RootDiskType) metal3api.DiskType {
 	if diskdata.Rotational {
 		return metal3api.HDD
 	}
@@ -97,7 +105,7 @@ func getDiskType(diskdata introspection.RootDiskType) metal3api.DiskType {
 	return metal3api.SSD
 }
 
-func getStorageDetails(diskdata []introspection.RootDiskType) []metal3api.Storage {
+func getStorageDetails(diskdata []inventory.RootDiskType) []metal3api.Storage {
 	storage := make([]metal3api.Storage, len(diskdata))
 	for i, disk := range diskdata {
 		device := disk.Name
@@ -121,7 +129,7 @@ func getStorageDetails(diskdata []introspection.RootDiskType) []metal3api.Storag
 	return storage
 }
 
-func getSystemVendorDetails(vendor introspection.SystemVendorType) metal3api.HardwareSystemVendor {
+func getSystemVendorDetails(vendor inventory.SystemVendorType) metal3api.HardwareSystemVendor {
 	return metal3api.HardwareSystemVendor{
 		Manufacturer: vendor.Manufacturer,
 		ProductName:  vendor.ProductName,
@@ -129,7 +137,7 @@ func getSystemVendorDetails(vendor introspection.SystemVendorType) metal3api.Har
 	}
 }
 
-func getCPUDetails(cpudata *introspection.CPUType) metal3api.CPU {
+func getCPUDetails(cpudata *inventory.CPUType) metal3api.CPU {
 	var freq float64
 	fmt.Sscanf(cpudata.Frequency, "%f", &freq)
 	freq = math.Round(freq) // Ensure freq has no fractional part
@@ -145,7 +153,7 @@ func getCPUDetails(cpudata *introspection.CPUType) metal3api.CPU {
 	return cpu
 }
 
-func getFirmwareDetails(firmwaredata introspection.SystemFirmwareType) metal3api.Firmware {
+func getFirmwareDetails(firmwaredata inventory.SystemFirmwareType) metal3api.Firmware {
 	return metal3api.Firmware{
 		BIOS: metal3api.BIOS{
 			Vendor:  firmwaredata.Vendor,
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index b60370eb..162b204c 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -12,7 +12,6 @@ import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -98,8 +97,6 @@ type ironicProvisioner struct {
 	bootMACAddress string
 	// a client for talking to ironic
 	client *gophercloud.ServiceClient
-	// a client for talking to ironic-inspector
-	inspector *gophercloud.ServiceClient
 	// a logger configured for this host
 	log logr.Logger
 	// a debug logger configured for this host
@@ -844,8 +841,8 @@ func (p *ironicProvisioner) InspectHardware(data provisioner.InspectData, restar
 		return
 	}
 
-	// TODO(dtantsur): change this to use Ironic native inspection data API.
-	response := introspection.GetIntrospectionData(p.inspector, ironicNode.UUID)
+	p.log.Info("getting hardware details from inspection")
+	response := nodes.GetInventory(p.client, ironicNode.UUID)
 	introData, err := response.Extract()
 	if err != nil {
 		if _, isNotFound := err.(gophercloud.ErrDefault404); isNotFound {
@@ -860,7 +857,7 @@ func (p *ironicProvisioner) InspectHardware(data provisioner.InspectData, restar
 	// Introspection is done
 	p.log.Info("inspection finished successfully", "data", response.Body)
 
-	details = hardwaredetails.GetHardwareDetails(introData)
+	details = hardwaredetails.GetHardwareDetails(introData, p.log)
 	p.publisher("InspectionComplete", "Hardware inspection completed")
 	result, err = operationComplete()
 	return
@@ -1966,7 +1963,7 @@ func ironicNodeName(objMeta metav1.ObjectMeta) string {
 func (p *ironicProvisioner) IsReady() (result bool, err error) {
 	p.debugLog.Info("verifying ironic provisioner dependencies")
 
-	checker := newIronicDependenciesChecker(p.client, p.inspector, p.log)
+	checker := newIronicDependenciesChecker(p.client, p.log)
 	return checker.IsReady()
 }
 


Test patch:
diff --git a/pkg/provisioner/ironic/adopt_test.go b/pkg/provisioner/ironic/adopt_test.go
index 53716c9b..d203528f 100644
--- a/pkg/provisioner/ironic/adopt_test.go
+++ b/pkg/provisioner/ironic/adopt_test.go
@@ -5,7 +5,6 @@ import (
 	"time"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
@@ -128,19 +127,11 @@ func TestAdopt(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/bios_test.go b/pkg/provisioner/ironic/bios_test.go
index b7227f22..d062eec6 100644
--- a/pkg/provisioner/ironic/bios_test.go
+++ b/pkg/provisioner/ironic/bios_test.go
@@ -100,18 +100,13 @@ func TestGetFirmwareSettings(t *testing.T) {
 			tc.ironic.Start()
 			defer tc.ironic.Stop()
 
-			inspector := testserver.NewInspector(t).Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Name = "node-1"
 			host.Status.Provisioning.ID = nodeUUID
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
 
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/configdrive_test.go b/pkg/provisioner/ironic/configdrive_test.go
index 38c7f5ec..d2f6a1d0 100644
--- a/pkg/provisioner/ironic/configdrive_test.go
+++ b/pkg/provisioner/ironic/configdrive_test.go
@@ -4,7 +4,6 @@ import (
 	"testing"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	"github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
@@ -130,19 +129,11 @@ func TestEmpty(t *testing.T) {
 			ironic.Start()
 			defer ironic.Stop()
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/delete_test.go b/pkg/provisioner/ironic/delete_test.go
index 6603b36a..84ee54c1 100644
--- a/pkg/provisioner/ironic/delete_test.go
+++ b/pkg/provisioner/ironic/delete_test.go
@@ -29,10 +29,9 @@ func deleteTest(t *testing.T, detach bool) {
 	nodeUUID := "33ce8659-7400-4c68-9535-d10766f07a58"
 
 	cases := []struct {
-		name      string
-		ironic    *testserver.IronicMock
-		inspector *testserver.InspectorMock
-		hostName  string
+		name     string
+		ironic   *testserver.IronicMock
+		hostName string
 
 		expectedDirty        bool
 		expectedRequestAfter time.Duration
@@ -177,11 +176,6 @@ func deleteTest(t *testing.T, detach bool) {
 				defer tc.ironic.Stop()
 			}
 
-			if tc.inspector != nil {
-				tc.inspector.Start()
-				defer tc.inspector.Stop()
-			}
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 
@@ -190,9 +184,7 @@ func deleteTest(t *testing.T, detach bool) {
 			}
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				tc.ironic.Endpoint(), auth, tc.inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/factory_test.go b/pkg/provisioner/ironic/factory_test.go
index 639c6e28..952b0dd7 100644
--- a/pkg/provisioner/ironic/factory_test.go
+++ b/pkg/provisioner/ironic/factory_test.go
@@ -9,7 +9,6 @@ import (
 
 type EnvFixture struct {
 	ironicEndpoint                   string
-	inspectorEndpoint                string
 	kernelURL                        string
 	ramdiskURL                       string
 	isoURL                           string
@@ -40,7 +39,6 @@ func (f *EnvFixture) replace(env, value string) {
 func (f *EnvFixture) SetUp() {
 	f.origEnv = map[string]string{}
 	f.replace("IRONIC_ENDPOINT", f.ironicEndpoint)
-	f.replace("IRONIC_INSPECTOR_ENDPOINT", f.inspectorEndpoint)
 	f.replace("DEPLOY_KERNEL_URL", f.kernelURL)
 	f.replace("DEPLOY_RAMDISK_URL", f.ramdiskURL)
 	f.replace("DEPLOY_ISO_URL", f.isoURL)
@@ -54,9 +52,8 @@ func (f EnvFixture) VerifyConfig(t *testing.T, c ironicConfig, _ string) {
 	assert.Equal(t, f.liveISOForcePersistentBootDevice, c.liveISOForcePersistentBootDevice)
 }
 
-func (f EnvFixture) VerifyEndpoints(t *testing.T, ironic, inspector string) {
+func (f EnvFixture) VerifyEndpoints(t *testing.T, ironic string) {
 	assert.Equal(t, f.ironicEndpoint, ironic)
-	assert.Equal(t, f.inspectorEndpoint, inspector)
 }
 
 func TestLoadConfigFromEnv(t *testing.T) {
@@ -189,25 +186,12 @@ func TestLoadEndpointsFromEnv(t *testing.T) {
 		expectError bool
 	}{
 		{
-			name: "both",
-			env: EnvFixture{
-				ironicEndpoint:    "http://ironic.test",
-				inspectorEndpoint: "http://ironic-inspector.test",
-			},
-		}, {
-			name: "ironic-only",
+			name: "with-ironic",
 			env: EnvFixture{
 				ironicEndpoint: "http://ironic.test",
 			},
-			expectError: true,
-		}, {
-			name: "inspector-only",
-			env: EnvFixture{
-				inspectorEndpoint: "http://ironic-inspector.test",
-			},
-			expectError: true,
 		}, {
-			name:        "neither",
+			name:        "without-ironic",
 			env:         EnvFixture{},
 			expectError: true,
 		},
@@ -217,12 +201,12 @@ func TestLoadEndpointsFromEnv(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer tc.env.TearDown()
 			tc.env.SetUp()
-			i, ii, err := loadEndpointsFromEnv()
+			i, err := loadEndpointsFromEnv()
 			if tc.expectError {
 				assert.NotNil(t, err)
 			} else {
 				assert.Nil(t, err)
-				tc.env.VerifyEndpoints(t, i, ii)
+				tc.env.VerifyEndpoints(t, i)
 			}
 		})
 	}
diff --git a/pkg/provisioner/ironic/findhost_test.go b/pkg/provisioner/ironic/findhost_test.go
index fbdf1974..08c1eb63 100644
--- a/pkg/provisioner/ironic/findhost_test.go
+++ b/pkg/provisioner/ironic/findhost_test.go
@@ -63,9 +63,7 @@ func TestFindExistingHost(t *testing.T) {
 			host.ObjectMeta.Name = tc.hostName
 			host.Status.Provisioning.ID = tc.provisioningID
 
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-				tc.ironic.Endpoint(), auth, "https://inspector.test/", auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
index 14ad04bf..a3c68b64 100644
--- a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
+++ b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
@@ -4,6 +4,7 @@ import (
 	"reflect"
 	"testing"
 
+	"github.com/gophercloud/gophercloud/openstack/baremetal/inventory"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 
 	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
@@ -150,7 +151,7 @@ func TestGetVLANsMalformed(t *testing.T) {
 
 func TestGetNICDetails(t *testing.T) {
 	nics := getNICDetails(
-		[]introspection.InterfaceType{
+		[]inventory.InterfaceType{
 			{
 				Name:        "eth0",
 				IPV4Address: "192.0.2.1",
@@ -231,7 +232,7 @@ func TestGetNICDetails(t *testing.T) {
 
 func TestGetFirmwareDetails(t *testing.T) {
 	// Test full (known) firmware payload
-	firmware := getFirmwareDetails(introspection.SystemFirmwareType{
+	firmware := getFirmwareDetails(inventory.SystemFirmwareType{
 		Vendor:    "foobar",
 		Version:   "1.2.3",
 		BuildDate: "2019-07-10",
diff --git a/pkg/provisioner/ironic/inspecthardware_test.go b/pkg/provisioner/ironic/inspecthardware_test.go
index 52df2108..ab3d4db7 100644
--- a/pkg/provisioner/ironic/inspecthardware_test.go
+++ b/pkg/provisioner/ironic/inspecthardware_test.go
@@ -5,8 +5,8 @@ import (
 	"testing"
 	"time"
 
+	"github.com/gophercloud/gophercloud/openstack/baremetal/inventory"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
@@ -21,9 +21,8 @@ func TestInspectHardware(t *testing.T) {
 	nodeUUID := "33ce8659-7400-4c68-9535-d10766f07a58"
 
 	cases := []struct {
-		name      string
-		ironic    *testserver.IronicMock
-		inspector *testserver.InspectorMock
+		name   string
+		ironic *testserver.IronicMock
 
 		restartOnFailure bool
 		refresh          bool
@@ -54,8 +53,7 @@ func TestInspectHardware(t *testing.T) {
 			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
 				UUID:           nodeUUID,
 				ProvisionState: "manageable",
-			}),
-			inspector: testserver.NewInspector(t).Ready().WithIntrospectionDataFailed(nodeUUID, http.StatusNotFound),
+			}).WithInventoryFailed(nodeUUID, http.StatusNotFound),
 
 			expectedStarted:      true,
 			expectedDirty:        true,
@@ -67,13 +65,11 @@ func TestInspectHardware(t *testing.T) {
 			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
 				UUID:           nodeUUID,
 				ProvisionState: "manageable",
+			}).WithInventory(nodeUUID, nodes.InventoryData{
+				Inventory: inventory.InventoryType{
+					Hostname: "node-0",
+				},
 			}),
-			inspector: testserver.NewInspector(t).Ready().
-				WithIntrospectionData(nodeUUID, introspection.Data{
-					Inventory: introspection.InventoryType{
-						Hostname: "node-0",
-					},
-				}),
 
 			refresh: true,
 
@@ -87,10 +83,9 @@ func TestInspectHardware(t *testing.T) {
 			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
 				UUID:           nodeUUID,
 				ProvisionState: "manageable",
-			}),
-			inspector: testserver.NewInspector(t).Ready().WithIntrospectionDataFailed(nodeUUID, http.StatusBadRequest),
+			}).WithInventoryFailed(nodeUUID, http.StatusBadRequest),
 
-			expectedError: "failed to retrieve hardware introspection data: Bad request with: \\[GET http://127.0.0.1:.*/v1/introspection/33ce8659-7400-4c68-9535-d10766f07a58/data\\], error message: An error\\\n",
+			expectedError: "failed to retrieve hardware introspection data: Bad request with: \\[GET http://127.0.0.1:.*/v1/nodes/33ce8659-7400-4c68-9535-d10766f07a58/inventory\\], error message: An error\\\n",
 		},
 		{
 			name: "introspection-status-retry-on-wait",
@@ -192,13 +187,11 @@ func TestInspectHardware(t *testing.T) {
 			ironic: testserver.NewIronic(t).Ready().Node(nodes.Node{
 				UUID:           nodeUUID,
 				ProvisionState: string(nodes.Manageable),
+			}).WithInventory(nodeUUID, nodes.InventoryData{
+				Inventory: inventory.InventoryType{
+					Hostname: "node-0",
+				},
 			}),
-			inspector: testserver.NewInspector(t).Ready().
-				WithIntrospectionData(nodeUUID, introspection.Data{
-					Inventory: introspection.InventoryType{
-						Hostname: "node-0",
-					},
-				}),
 
 			expectedDirty:       false,
 			expectedDetailsHost: "node-0",
@@ -213,11 +206,6 @@ func TestInspectHardware(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			if tc.inspector != nil {
-				tc.inspector.Start()
-				defer tc.inspector.Stop()
-			}
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publishedMsg := ""
@@ -225,9 +213,7 @@ func TestInspectHardware(t *testing.T) {
 				publishedMsg = reason + " " + message
 			}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, tc.inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/ironic_test.go b/pkg/provisioner/ironic/ironic_test.go
index e816132c..89c1965b 100644
--- a/pkg/provisioner/ironic/ironic_test.go
+++ b/pkg/provisioner/ironic/ironic_test.go
@@ -37,7 +37,7 @@ func newTestProvisionerFactory() ironicProvisionerFactory {
 
 // A private function to construct an ironicProvisioner (rather than a
 // Provisioner interface) in a consistent way for tests.
-func newProvisionerWithSettings(host metal3api.BareMetalHost, bmcCreds bmc.Credentials, publisher provisioner.EventPublisher, ironicURL string, ironicAuthSettings clients.AuthConfig, inspectorURL string, inspectorAuthSettings clients.AuthConfig) (*ironicProvisioner, error) {
+func newProvisionerWithSettings(host metal3api.BareMetalHost, bmcCreds bmc.Credentials, publisher provisioner.EventPublisher, ironicURL string, ironicAuthSettings clients.AuthConfig) (*ironicProvisioner, error) {
 	hostData := provisioner.BuildHostData(host, bmcCreds)
 
 	tlsConf := clients.TLSConfig{}
@@ -46,14 +46,8 @@ func newProvisionerWithSettings(host metal3api.BareMetalHost, bmcCreds bmc.Crede
 		return nil, err
 	}
 
-	clientInspector, err := clients.InspectorClient(inspectorURL, inspectorAuthSettings, tlsConf)
-	if err != nil {
-		return nil, err
-	}
-
 	factory := newTestProvisionerFactory()
 	factory.clientIronic = clientIronic
-	factory.clientInspector = clientInspector
 	return factory.ironicProvisioner(hostData, publisher)
 }
 
diff --git a/pkg/provisioner/ironic/power_test.go b/pkg/provisioner/ironic/power_test.go
index 324a8e4e..2b097e24 100644
--- a/pkg/provisioner/ironic/power_test.go
+++ b/pkg/provisioner/ironic/power_test.go
@@ -7,7 +7,6 @@ import (
 	"time"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
@@ -111,19 +110,11 @@ func TestPowerOn(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -265,12 +256,6 @@ func TestPowerOff(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			var eventReasons []string
@@ -278,9 +263,7 @@ func TestPowerOff(t *testing.T) {
 				eventReasons = append(eventReasons, message)
 			}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -317,9 +300,6 @@ func TestSoftPowerOffFallback(t *testing.T) {
 	ironic := testserver.NewIronic(t).Ready().Node(node).WithNodeStatesPowerUpdate(nodeUUID, http.StatusBadRequest)
 	ironic.Start()
 	defer ironic.Stop()
-	inspector := testserver.NewInspector(t).Ready()
-	inspector.Start()
-	defer inspector.Stop()
 
 	host := makeHost()
 	host.Status.Provisioning.ID = nodeUUID
@@ -328,9 +308,7 @@ func TestSoftPowerOffFallback(t *testing.T) {
 		eventReasons = append(eventReasons, message)
 	}
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-		ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
diff --git a/pkg/provisioner/ironic/prepare_test.go b/pkg/provisioner/ironic/prepare_test.go
index 7d85302d..1ae1c5b7 100644
--- a/pkg/provisioner/ironic/prepare_test.go
+++ b/pkg/provisioner/ironic/prepare_test.go
@@ -6,7 +6,6 @@ import (
 	"time"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
@@ -173,12 +172,6 @@ func TestPrepare(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			prepData := provisioner.PrepareData{}
@@ -200,9 +193,7 @@ func TestPrepare(t *testing.T) {
 
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/provision_test.go b/pkg/provisioner/ironic/provision_test.go
index e206feee..c39b885e 100644
--- a/pkg/provisioner/ironic/provision_test.go
+++ b/pkg/provisioner/ironic/provision_test.go
@@ -6,7 +6,6 @@ import (
 	"time"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 	"k8s.io/apimachinery/pkg/util/intstr"
 
@@ -166,19 +165,11 @@ func TestProvision(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -303,19 +294,11 @@ func TestDeprovision(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -435,12 +418,6 @@ func TestIronicHasSameImage(t *testing.T) {
 			ironic.Start()
 			defer ironic.Stop()
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			var host v1alpha1.BareMetalHost
 			if tc.liveImage {
 				host = makeHostLiveIso()
@@ -454,9 +431,7 @@ func TestIronicHasSameImage(t *testing.T) {
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -664,19 +639,11 @@ func TestBuildCleanSteps(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			inspector := testserver.NewInspector(t).Ready().WithIntrospection(nodeUUID, introspection.Introspection{
-				Finished: false,
-			})
-			inspector.Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			publisher := func(reason, message string) {}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/provisioncapacity_test.go b/pkg/provisioner/ironic/provisioncapacity_test.go
index ca131080..ec3ace0f 100644
--- a/pkg/provisioner/ironic/provisioncapacity_test.go
+++ b/pkg/provisioner/ironic/provisioncapacity_test.go
@@ -92,9 +92,6 @@ func TestHasCapacity(t *testing.T) {
 			ironic := testserver.NewIronic(t).Nodes(allNodes).Start()
 			defer ironic.Stop()
 
-			inspector := testserver.NewInspector(t).Start()
-			defer inspector.Stop()
-
 			host := makeHost()
 			host.Name = tc.hostName
 			if tc.bmcAddress != "" {
@@ -103,9 +100,7 @@ func TestHasCapacity(t *testing.T) {
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
 
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				ironic.Endpoint(), auth, inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/ready_test.go b/pkg/provisioner/ironic/ready_test.go
index 69782661..a7007fcf 100644
--- a/pkg/provisioner/ironic/ready_test.go
+++ b/pkg/provisioner/ironic/ready_test.go
@@ -14,62 +14,40 @@ import (
 func TestProvisionerIsReady(t *testing.T) {
 
 	cases := []struct {
-		name      string
-		ironic    *testserver.IronicMock
-		inspector *testserver.InspectorMock
+		name   string
+		ironic *testserver.IronicMock
 
-		expectedIronicCalls    string
-		expectedInspectorCalls string
-		expectedIsReady        bool
-		expectedError          string
+		expectedIronicCalls string
+		expectedIsReady     bool
+		expectedError       string
 	}{
 		{
-			name:                   "IsReady",
-			ironic:                 testserver.NewIronic(t).Ready().WithDrivers(),
-			inspector:              testserver.NewInspector(t).Ready(),
-			expectedIronicCalls:    "/v1;/v1/drivers;",
-			expectedInspectorCalls: "/v1;",
-			expectedIsReady:        true,
+			name:                "IsReady",
+			ironic:              testserver.NewIronic(t).Ready().WithDrivers(),
+			expectedIronicCalls: "/v1;/v1/drivers;",
+			expectedIsReady:     true,
 		},
 		{
 			name:                "NoDriversLoaded",
 			ironic:              testserver.NewIronic(t).Ready(),
-			inspector:           testserver.NewInspector(t).Ready(),
 			expectedIronicCalls: "/v1;/v1/drivers;",
 		},
 		{
 			name:            "IronicDown",
-			inspector:       testserver.NewInspector(t).Ready(),
 			expectedIsReady: false,
 		},
-		{
-			name:                "InspectorDown",
-			ironic:              testserver.NewIronic(t).Ready().WithDrivers(),
-			expectedIronicCalls: "/v1;/v1/drivers;",
-			expectedIsReady:     false,
-		},
 		{
 			name:                "IronicNotOk",
 			ironic:              testserver.NewIronic(t).NotReady(http.StatusInternalServerError),
-			inspector:           testserver.NewInspector(t).Ready(),
 			expectedIsReady:     false,
 			expectedIronicCalls: "/v1;",
 		},
 		{
 			name:                "IronicNotOkAndNotExpected",
 			ironic:              testserver.NewIronic(t).NotReady(http.StatusBadGateway),
-			inspector:           testserver.NewInspector(t).Ready(),
 			expectedIsReady:     false,
 			expectedIronicCalls: "/v1;",
 		},
-		{
-			name:                   "InspectorNotOk",
-			ironic:                 testserver.NewIronic(t).Ready().WithDrivers(),
-			inspector:              testserver.NewInspector(t).NotReady(http.StatusInternalServerError),
-			expectedIsReady:        false,
-			expectedIronicCalls:    "/v1;/v1/drivers;",
-			expectedInspectorCalls: "/v1;",
-		},
 	}
 
 	for _, tc := range cases {
@@ -79,18 +57,10 @@ func TestProvisionerIsReady(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			if tc.inspector != nil {
-				tc.inspector.Start()
-				defer tc.inspector.Stop()
-			}
-
 			auth := clients.AuthConfig{Type: clients.NoAuth}
 
 			ironicEndpoint := tc.ironic.Endpoint()
-			inspectorEndpoint := tc.inspector.Endpoint()
-			prov, err := newProvisionerWithSettings(makeHost(), bmc.Credentials{}, nil,
-				ironicEndpoint, auth, inspectorEndpoint, auth,
-			)
+			prov, err := newProvisionerWithSettings(makeHost(), bmc.Credentials{}, nil, ironicEndpoint, auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -103,9 +73,6 @@ func TestProvisionerIsReady(t *testing.T) {
 			if tc.ironic != nil {
 				assert.Equal(t, tc.expectedIronicCalls, tc.ironic.Requests, "ironic calls")
 			}
-			if tc.inspector != nil {
-				assert.Equal(t, tc.expectedInspectorCalls, tc.inspector.Requests, "inspector calls")
-			}
 
 			if tc.expectedError != "" {
 				assert.Regexp(t, tc.expectedError, err, "error message")
diff --git a/pkg/provisioner/ironic/testserver/inspector.go b/pkg/provisioner/ironic/testserver/inspector.go
deleted file mode 100644
index 20fb9dbf..00000000
--- a/pkg/provisioner/ironic/testserver/inspector.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package testserver
-
-import (
-	"net/http"
-	"testing"
-
-	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
-)
-
-// InspectorMock is a test server that implements Ironic Inspector's semantics
-type InspectorMock struct {
-	*MockServer
-}
-
-// NewInspector builds a new inspector mock server
-func NewInspector(t *testing.T) *InspectorMock {
-	return &InspectorMock{
-		New(t, "inspector"),
-	}
-}
-
-// Endpoint returns the URL to the server
-func (m *InspectorMock) Endpoint() string {
-	if m == nil {
-		return "https://inspector.test/v1/"
-	}
-	return m.MockServer.Endpoint()
-}
-
-// Ready configures the server with a valid response for /v1
-func (m *InspectorMock) Ready() *InspectorMock {
-	m.ResponseWithCode("/v1", "{}", http.StatusOK)
-	return m
-}
-
-// NotReady configures the server with an error response for /v1
-func (m *InspectorMock) NotReady(errorCode int) *InspectorMock {
-	m.ErrorResponse("/v1", errorCode)
-	return m
-}
-
-// WithIntrospection configures the server with a valid response for /v1/introspection/<node>
-func (m *InspectorMock) WithIntrospection(nodeUUID string, status introspection.Introspection) *InspectorMock {
-	m.ResponseJSON("/v1/introspection/"+nodeUUID, status)
-	return m
-}
-
-// WithIntrospectionFailed configures the server with an error response for /v1/introspection/<node>
-func (m *InspectorMock) WithIntrospectionFailed(nodeUUID string, errorCode int) *InspectorMock {
-	m.ErrorResponse("/v1/introspection/"+nodeUUID, errorCode)
-	return m
-}
-
-// WithIntrospectionData configures the server with a valid response for /v1/introspection/<node>/data
-func (m *InspectorMock) WithIntrospectionData(nodeUUID string, data introspection.Data) *InspectorMock {
-	m.ResponseJSON("/v1/introspection/"+nodeUUID+"/data", data)
-	return m
-}
-
-// WithIntrospectionDataFailed configures the server with an error response for /v1/introspection/<node>/data
-func (m *InspectorMock) WithIntrospectionDataFailed(nodeUUID string, errorCode int) *InspectorMock {
-	m.ErrorResponse("/v1/introspection/"+nodeUUID+"/data", errorCode)
-	return m
-}
diff --git a/pkg/provisioner/ironic/testserver/ironic.go b/pkg/provisioner/ironic/testserver/ironic.go
index 504be4ac..a287228c 100644
--- a/pkg/provisioner/ironic/testserver/ironic.go
+++ b/pkg/provisioner/ironic/testserver/ironic.go
@@ -446,3 +446,15 @@ func (m *IronicMock) BIOSDetailSettings(nodeUUID string) *IronicMock {
 func (m *IronicMock) NoBIOS(nodeUUID string) *IronicMock {
 	return m.NodeError(nodeUUID, http.StatusNotFound)
 }
+
+// WithInventory configures the server with a valid response for /v1/nodes/<node>/inventory
+func (m *IronicMock) WithInventory(nodeUUID string, data nodes.InventoryData) *IronicMock {
+	m.ResponseJSON("/v1/nodes/"+nodeUUID+"/inventory", data)
+	return m
+}
+
+// WithInventoryFailed configures the server with an error response for /v1/nodes/<node>/inventory
+func (m *IronicMock) WithInventoryFailed(nodeUUID string, errorCode int) *IronicMock {
+	m.ErrorResponse("/v1/nodes/"+nodeUUID+"/inventory", errorCode)
+	return m
+}
diff --git a/pkg/provisioner/ironic/updatehardwarestate_test.go b/pkg/provisioner/ironic/updatehardwarestate_test.go
index 44a8442e..ab2b13b6 100644
--- a/pkg/provisioner/ironic/updatehardwarestate_test.go
+++ b/pkg/provisioner/ironic/updatehardwarestate_test.go
@@ -19,7 +19,6 @@ func TestUpdateHardwareState(t *testing.T) {
 	cases := []struct {
 		name                 string
 		ironic               *testserver.IronicMock
-		inspector            *testserver.InspectorMock
 		hostCurrentlyPowered bool
 		hostName             string
 
@@ -113,11 +112,6 @@ func TestUpdateHardwareState(t *testing.T) {
 				defer tc.ironic.Stop()
 			}
 
-			if tc.inspector != nil {
-				tc.inspector.Start()
-				defer tc.inspector.Stop()
-			}
-
 			host := makeHost()
 			host.Status.Provisioning.ID = nodeUUID
 			host.Status.PoweredOn = tc.hostCurrentlyPowered
@@ -130,9 +124,7 @@ func TestUpdateHardwareState(t *testing.T) {
 				publishedMsg = reason + " " + message
 			}
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher,
-				tc.ironic.Endpoint(), auth, tc.inspector.Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, publisher, tc.ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
diff --git a/pkg/provisioner/ironic/updateopts_test.go b/pkg/provisioner/ironic/updateopts_test.go
index 0bf6fc2f..a66d0e95 100644
--- a/pkg/provisioner/ironic/updateopts_test.go
+++ b/pkg/provisioner/ironic/updateopts_test.go
@@ -457,9 +457,7 @@ func TestGetUpdateOptsForNodeWithRootHints(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHost()
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -552,9 +550,7 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 	eventPublisher := func(reason, message string) {}
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(errors.Wrap(err, "could not create provisioner"))
 	}
@@ -651,9 +647,7 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 	eventPublisher := func(reason, message string) {}
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -722,9 +716,7 @@ func TestGetUpdateOptsForNodeLiveIso(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHostLiveIso()
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -785,9 +777,7 @@ func TestGetUpdateOptsForNodeImageToLiveIso(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHostLiveIso()
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -866,9 +856,7 @@ func TestGetUpdateOptsForNodeLiveIsoToImage(t *testing.T) {
 	host.Spec.Image.URL = "newimage"
 	host.Spec.Image.Checksum = "thechecksum"
 	host.Spec.Image.ChecksumType = metal3api.MD5
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -944,9 +932,7 @@ func TestGetUpdateOptsForNodeCustomDeploy(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHostCustomDeploy(true)
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1003,9 +989,7 @@ func TestGetUpdateOptsForNodeCustomDeployWithImage(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHostCustomDeploy(false)
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1066,9 +1050,7 @@ func TestGetUpdateOptsForNodeImageToCustomDeploy(t *testing.T) {
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
 	host := makeHostCustomDeploy(false)
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1166,9 +1148,7 @@ func TestGetUpdateOptsForNodeSecureBoot(t *testing.T) {
 	eventPublisher := func(reason, message string) {}
 	auth := clients.AuthConfig{Type: clients.NoAuth}
 
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher,
-		"https://ironic.test", auth, "https://ironic.test", auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, eventPublisher, "https://ironic.test", auth)
 	if err != nil {
 		t.Fatal(errors.Wrap(err, "could not create provisioner"))
 	}
diff --git a/pkg/provisioner/ironic/validatemanagementaccess_test.go b/pkg/provisioner/ironic/validatemanagementaccess_test.go
index 44c08c01..bb914877 100644
--- a/pkg/provisioner/ironic/validatemanagementaccess_test.go
+++ b/pkg/provisioner/ironic/validatemanagementaccess_test.go
@@ -30,9 +30,7 @@ func TestValidateManagementAccessNoMAC(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -62,9 +60,7 @@ func TestValidateManagementAccessMACOptional(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -96,9 +92,7 @@ func TestValidateManagementAccessCreateNodeNoImage(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -132,9 +126,7 @@ func TestValidateManagementAccessCreateWithImage(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -170,9 +162,7 @@ func TestValidateManagementAccessCreateWithLiveIso(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -211,9 +201,7 @@ func TestValidateManagementAccessExistingNode(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -248,9 +236,7 @@ func TestValidateManagementAccessExistingNodeNameUpdate(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -323,9 +309,7 @@ func TestValidateManagementAccessExistingNodeContinue(t *testing.T) {
 			defer ironic.Stop()
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -436,9 +420,7 @@ func TestValidateManagementAccessExistingSteadyStateNoUpdate(t *testing.T) {
 			defer ironic.Stop()
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -494,9 +476,7 @@ func TestValidateManagementAccessExistingNodeWaiting(t *testing.T) {
 			defer ironic.Stop()
 
 			auth := clients.AuthConfig{Type: clients.NoAuth}
-			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-				ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-			)
+			prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 			if err != nil {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
@@ -552,9 +532,7 @@ func TestValidateManagementAccessNewCredentials(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -601,9 +579,7 @@ func TestValidateManagementAccessLinkExistingIronicNodeByMAC(t *testing.T) {
 	host.Status.Provisioning.ID = "" // so we don't lookup by uuid
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -645,9 +621,7 @@ func TestValidateManagementAccessExistingPortWithWrongUUID(t *testing.T) {
 	host.Status.Provisioning.ID = "" // so we don't lookup by uuid
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -690,9 +664,7 @@ func TestValidateManagementAccessExistingPortButHasName(t *testing.T) {
 	host.Status.Provisioning.ID = "" // so we don't lookup by uuid
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -730,9 +702,7 @@ func TestValidateManagementAccessAddTwoHostsWithSameMAC(t *testing.T) {
 	host.Status.Provisioning.ID = "" // so we don't lookup by uuid
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -757,9 +727,7 @@ func TestValidateManagementAccessUnsupportedSecureBoot(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -780,9 +748,7 @@ func TestValidateManagementAccessNoBMCDetails(t *testing.T) {
 	host.Spec.BMC = metal3api.BMCDetails{}
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -805,9 +771,7 @@ func TestValidateManagementAccessMalformedBMCAddress(t *testing.T) {
 	}
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nullEventPublisher, ironic.Endpoint(), auth)
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
 	}
@@ -858,10 +822,7 @@ func TestPreprovisioningImageFormats(t *testing.T) {
 			host := makeHost()
 			host.Spec.BMC.Address = tc.Address
 
-			prov, _ := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-				ironicEndpoint, auth,
-				ironicEndpoint, auth,
-			)
+			prov, _ := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironicEndpoint, auth)
 			prov.config.havePreprovImgBuilder = tc.PreprovImgEnabled
 
 			fmts, err := prov.PreprovisioningImageFormats()
@@ -1163,9 +1124,7 @@ func TestSetExternalURL(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
@@ -1195,9 +1154,7 @@ func TestSetExternalURLIPv4(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)
@@ -1227,9 +1184,7 @@ func TestSetExternalURLRemoving(t *testing.T) {
 	defer ironic.Stop()
 
 	auth := clients.AuthConfig{Type: clients.NoAuth}
-	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil,
-		ironic.Endpoint(), auth, testserver.NewInspector(t).Endpoint(), auth,
-	)
+	prov, err := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironic.Endpoint(), auth)
 
 	if err != nil {
 		t.Fatalf("could not create provisioner: %s", err)