1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 15:47:14 +01:00

baremetal: Add diagnostic error message for ironic terraform errors

This PR enables the installer to track certain ironic terraform provider error messages and translates it into easy-to-understand errors output by the installer.

Examples:
Terraform errors such as "Error: could not contact Ironic API: timeout reached" and "Error: could not inspect: could not inspect node, node is currently 'inspect failed', last error was 'timeout reached while inspecting the node" will each get translated to their corresponding user-friendly error messages.
This commit is contained in:
Kiran Thyagaraja
2020-07-21 17:57:44 -05:00
parent e1a76aba96
commit 17be09f2f0
19 changed files with 376 additions and 94 deletions

5
go.mod
View File

@@ -29,7 +29,7 @@ require (
github.com/golang/protobuf v1.4.1
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible // indirect
github.com/google/uuid v1.1.1
github.com/gophercloud/gophercloud v0.11.0
github.com/gophercloud/gophercloud v0.12.0
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c
github.com/h2non/filetype v1.0.12
github.com/hashicorp/go-azure-helpers v0.10.0
@@ -47,7 +47,8 @@ require (
github.com/metal3-io/baremetal-operator v0.0.0
github.com/metal3-io/cluster-api-provider-baremetal v0.0.0
github.com/mitchellh/cli v1.1.1
github.com/openshift-metal3/terraform-provider-ironic v0.2.2
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 // indirect
github.com/openshift-metal3/terraform-provider-ironic v0.2.3
github.com/openshift/api v3.9.1-0.20191111211345-a27ff30ebf09+incompatible
github.com/openshift/client-go v0.0.0-20200320150128-a906f3d8e723
github.com/openshift/cloud-credential-operator v0.0.0-20200316201045-d10080b52c9e

5
go.sum
View File

@@ -834,6 +834,8 @@ github.com/gophercloud/gophercloud v0.7.1-0.20191210042042-7aa2e52d21f9/go.mod h
github.com/gophercloud/gophercloud v0.10.1-0.20200424014253-c3bfe50899e5/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
github.com/gophercloud/gophercloud v0.11.0 h1:pYMP9UZBdQa3lsfIZ1tZor4EbtxiuB6BHhocenkiH/E=
github.com/gophercloud/gophercloud v0.11.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
github.com/gophercloud/gophercloud v0.12.0 h1:mZrie07npp6ODiwHZolTicr5jV8Ogn43AvAsSMm6Ork=
github.com/gophercloud/gophercloud v0.12.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
github.com/gophercloud/utils v0.0.0-20190124231947-9c3b9f2457ef/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw=
github.com/gophercloud/utils v0.0.0-20190313033024-0bcc8e728cb5/go.mod h1:SZ9FTKibIotDtCrxAU/evccoyu1yhKST6hgBvwTB5Eg=
github.com/gophercloud/utils v0.0.0-20191129022341-463e26ffa30d/go.mod h1:SZ9FTKibIotDtCrxAU/evccoyu1yhKST6hgBvwTB5Eg=
@@ -1386,6 +1388,7 @@ github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU=
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@@ -1402,6 +1405,8 @@ github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOl
github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/openshift-metal3/terraform-provider-ironic v0.2.2 h1:uXuZ/dcqhYfhpSblIvu5MU1DHgp1AndZG5wEvNFqL0U=
github.com/openshift-metal3/terraform-provider-ironic v0.2.2/go.mod h1:cjkJ6u5ae+MEaiESbtkiWReOrd0dMkSxQlJbQnPKXU0=
github.com/openshift-metal3/terraform-provider-ironic v0.2.3 h1:16pF9y0RN+8jz9h4EUBz5Uv1dhUTPcHrTKz4nzQdd3Q=
github.com/openshift-metal3/terraform-provider-ironic v0.2.3/go.mod h1:ux2W6gsCIYsY/fX5N0V0ZgwFEBNN7P8g6RlH6ACi97k=
github.com/openshift/api v0.0.0-20200601094953-95abe2d2f422 h1:tgKcQVgHscJFBji1uLH5KjA81fGxNQkom5lETA5VURs=
github.com/openshift/api v0.0.0-20200601094953-95abe2d2f422/go.mod h1:l6TGeqJ92DrZBuWMNKcot1iZUHfbYSJyBWHGgg6Dn6s=
github.com/openshift/baremetal-operator v0.0.0-20200702005656-4ce920a36861 h1:6bDJzmU92kE82UPjVKiO7WM5L4rhbaeuwd0P6GRfEuM=

View File

@@ -78,4 +78,14 @@ var conditions = []condition{{
reason: "GCPComputeBackendTimeout",
message: `GCP is experiencing backend service interuptions, the compute instance failed to create in reasonable time.`,
}, {
match: regexp.MustCompile(`Error: could not contact Ironic API: timeout reached`),
reason: "BaremetalIronicAPITimeout",
message: `Timed out waiting for provisioning service. This failure can be caused by misconfiguration or inability to download the machine operating system images. Please check the bootstrap host for failing services.`,
}, {
match: regexp.MustCompile(`Error: could not inspect: could not inspect node, node is currently 'inspect failed', last error was 'timeout reached while inspecting the node'`),
reason: "BaremetalIronicInspectTimeout",
message: `Timed out waiting for node inspection to complete. Please check the console on the host for more details.`,
}}

View File

@@ -89,6 +89,24 @@ Error: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: St
`,
err: `error\(AzureQuotaLimitExceeded\) from Infrastructure Provider: Service limits exceeded for Virtual Machine cores in the the subscriptions for the region\. Requesting increase in quota should fix the error\.`,
}, {
input: `
Error: could not contact Ironic API: timeout reached
on ../../../../tmp/openshift-install-431515935/masters/main.tf line 1, in resource "ironic_node_v1" "openshift-master-host":
1: resource "ironic_node_v1" "openshift-master-host" {
`,
err: `error\(BaremetalIronicAPITimeout\) from Infrastructure Provider: Timed out waiting for provisioning service\. This failure can be caused by misconfiguration or inability to download the machine operating system images\. Please check the bootstrap host for failing services\.`,
}, {
input: `
Error: could not inspect: could not inspect node, node is currently 'inspect failed', last error was 'timeout reached while inspecting the node'
on ../../tmp/openshift-install-229338618/masters/main.tf line 1, in resource "ironic_node_v1" "openshift-master-host":
1: resource "ironic_node_v1" "openshift-master-host" {
`,
err: `error\(BaremetalIronicInspectTimeout\) from Infrastructure Provider: Timed out waiting for node inspection to complete\. Please check the console on the host for more details\.`,
}}
for _, test := range cases {

View File

@@ -36,6 +36,7 @@
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on rocky branch
nodeset: ubuntu-xenial
vars:
global_env:
OS_BRANCH: stable/rocky
@@ -45,6 +46,7 @@
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on queens branch
nodeset: ubuntu-xenial
vars:
global_env:
OS_BRANCH: stable/queens
@@ -54,6 +56,7 @@
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on pike branch
nodeset: ubuntu-xenial
vars:
global_env:
OS_BRANCH: stable/pike
@@ -63,6 +66,7 @@
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on ocata branch
nodeset: ubuntu-xenial
vars:
global_env:
OS_BRANCH: stable/ocata
@@ -72,6 +76,7 @@
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on newton branch
nodeset: ubuntu-xenial
vars:
global_env:
OS_BRANCH: stable/newton

View File

@@ -1,4 +1,25 @@
## 0.12.0 (Unreleased)
## 0.13.0 (Unlreleased)
## 0.12.0 (June 25, 2020)
UPGRADE NOTES
* The URL used in the `compute/v2/extensions/bootfromvolume` package has been changed from `os-volumes_boot` to `servers`.
IMPROVEMENTS
* The URL used in the `compute/v2/extensions/bootfromvolume` package has been changed from `os-volumes_boot` to `servers` [GH-1973](https://github.com/gophercloud/gophercloud/pull/1973)
* Modify `baremetal/v1/nodes.LogicalDisk.PhysicalDisks` type to support physical disks hints [GH-1982](https://github.com/gophercloud/gophercloud/pull/1982)
* Added `baremetalintrospection/httpbasic` which provides an HTTP Basic Auth client [GH-1986](https://github.com/gophercloud/gophercloud/pull/1986)
* Added `baremetal/httpbasic` which provides an HTTP Basic Auth client [GH-1983](https://github.com/gophercloud/gophercloud/pull/1983)
* Added `containerinfra/v1/clusters.CreateOpts.MergeLabels` [GH-1985](https://github.com/gophercloud/gophercloud/pull/1985)
BUG FIXES
* Changed `containerinfra/v1/clusters.Cluster.HealthStatusReason` from `string` to `map[string]interface{}` [GH-1968](https://github.com/gophercloud/gophercloud/pull/1968)
* Fixed marshalling of `blockstorage/extensions/backups.ImportBackup.Metadata` [GH-1967](https://github.com/gophercloud/gophercloud/pull/1967)
* Fixed typo of "OAUth" to "OAuth" in `identity/v3/extensions/oauth1` [GH-1969](https://github.com/gophercloud/gophercloud/pull/1969)
* Fixed goroutine leak during reauthentication [GH-1978](https://github.com/gophercloud/gophercloud/pull/1978)
## 0.11.0 (May 14, 2020)

View File

@@ -0,0 +1,18 @@
/*
Package httpbasic provides support for http_basic bare metal endpoints.
Example of obtaining and using a client:
client, err := httpbasic.NewBareMetalHTTPBasic(httpbasic.Endpoints{
IronicEndpoing: "http://localhost:6385/v1/",
IronicUser: "myUser",
IronicUserPassword: "myPassword",
})
if err != nil {
panic(err)
}
client.Microversion = "1.50"
nodes.ListDetail(client, nodes.listOpts{})
*/
package httpbasic

View File

@@ -0,0 +1,45 @@
package httpbasic
import (
"encoding/base64"
"fmt"
"github.com/gophercloud/gophercloud"
)
// EndpointOpts specifies a "http_basic" Ironic Endpoint
type EndpointOpts struct {
IronicEndpoint string
IronicUser string
IronicUserPassword string
}
func initClientOpts(client *gophercloud.ProviderClient, eo EndpointOpts) (*gophercloud.ServiceClient, error) {
sc := new(gophercloud.ServiceClient)
if eo.IronicEndpoint == "" {
return nil, fmt.Errorf("IronicEndpoint is required")
}
if eo.IronicUser == "" || eo.IronicUserPassword == "" {
return nil, fmt.Errorf("User and Password are required")
}
token := []byte(eo.IronicUser + ":" + eo.IronicUserPassword)
encodedToken := base64.StdEncoding.EncodeToString(token)
sc.MoreHeaders = map[string]string{"Authorization": "Basic " + encodedToken}
sc.Endpoint = gophercloud.NormalizeURL(eo.IronicEndpoint)
sc.ProviderClient = client
return sc, nil
}
// NewBareMetalHTTPBasic creates a ServiceClient that may be used to access a
// "http_basic" bare metal service.
func NewBareMetalHTTPBasic(eo EndpointOpts) (*gophercloud.ServiceClient, error) {
sc, err := initClientOpts(&gophercloud.ProviderClient{}, eo)
if err != nil {
return nil, err
}
sc.Type = "baremetal"
return sc, nil
}

View File

@@ -568,7 +568,7 @@ type LogicalDisk struct {
Controller string `json:"controller,omitempty"`
// A list of physical disks to use as read by the RAID interface.
PhysicalDisks []string `json:"physical_disks,omitempty"`
PhysicalDisks []interface{} `json:"physical_disks,omitempty"`
}
func (opts RAIDConfigOpts) ToRAIDConfigMap() (map[string]interface{}, error) {
@@ -577,10 +577,12 @@ func (opts RAIDConfigOpts) ToRAIDConfigMap() (map[string]interface{}, error) {
return nil, err
}
for _, v := range body["logical_disks"].([]interface{}) {
if logicalDisk, ok := v.(map[string]interface{}); ok {
if logicalDisk["size_gb"] == nil {
logicalDisk["size_gb"] = "MAX"
if body["logical_disks"] != nil {
for _, v := range body["logical_disks"].([]interface{}) {
if logicalDisk, ok := v.(map[string]interface{}); ok {
if logicalDisk["size_gb"] == nil {
logicalDisk["size_gb"] = "MAX"
}
}
}
}

View File

@@ -0,0 +1,17 @@
/*
Package httpbasic provides support for http_basic bare metal introspection endpoints.
Example of obtaining and using a client:
client, err := httpbasic.NewBareMetalIntrospectionHTTPBasic(httpbasic.EndpointOpts{
IronicInspectorEndpoint: "http://localhost:5050/v1/",
IronicInspectorUser: "myUser",
IronicInspectorUserPassword: "myPassword",
})
if err != nil {
panic(err)
}
introspection.GetIntrospectionStatus(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8")
*/
package httpbasic

View File

@@ -0,0 +1,45 @@
package httpbasic
import (
"encoding/base64"
"fmt"
"github.com/gophercloud/gophercloud"
)
// EndpointOpts specifies a "http_basic" Ironic Inspector Endpoint.
type EndpointOpts struct {
IronicInspectorEndpoint string
IronicInspectorUser string
IronicInspectorUserPassword string
}
func initClientOpts(client *gophercloud.ProviderClient, eo EndpointOpts) (*gophercloud.ServiceClient, error) {
sc := new(gophercloud.ServiceClient)
if eo.IronicInspectorEndpoint == "" {
return nil, fmt.Errorf("IronicInspectorEndpoint is required")
}
if eo.IronicInspectorUser == "" || eo.IronicInspectorUserPassword == "" {
return nil, fmt.Errorf("User and Password are required")
}
token := []byte(eo.IronicInspectorUser + ":" + eo.IronicInspectorUserPassword)
encodedToken := base64.StdEncoding.EncodeToString(token)
sc.MoreHeaders = map[string]string{"Authorization": "Basic " + encodedToken}
sc.Endpoint = gophercloud.NormalizeURL(eo.IronicInspectorEndpoint)
sc.ProviderClient = client
return sc, nil
}
// NewBareMetalIntrospectionHTTPBasic creates a ServiceClient that may be used to access a
// "http_basic" bare metal introspection service.
func NewBareMetalIntrospectionHTTPBasic(eo EndpointOpts) (*gophercloud.ServiceClient, error) {
sc, err := initClientOpts(&gophercloud.ProviderClient{}, eo)
if err != nil {
return nil, err
}
sc.Type = "baremetal-inspector"
return sc, nil
}

View File

@@ -3,5 +3,5 @@ package bootfromvolume
import "github.com/gophercloud/gophercloud"
func createURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("os-volumes_boot")
return c.ServiceURL("servers")
}

View File

@@ -26,6 +26,7 @@ type CreateOpts struct {
FloatingIPEnabled *bool `json:"floating_ip_enabled,omitempty"`
FixedNetwork string `json:"fixed_network,omitempty"`
FixedSubnet string `json:"fixed_subnet,omitempty"`
MergeLabels *bool `json:"merge_labels,omitempty"`
}
// ToClusterCreateMap constructs a request body from CreateOpts.

View File

@@ -69,37 +69,37 @@ func (r ResizeResult) Extract() (string, error) {
}
type Cluster struct {
APIAddress string `json:"api_address"`
COEVersion string `json:"coe_version"`
ClusterTemplateID string `json:"cluster_template_id"`
ContainerVersion string `json:"container_version"`
CreateTimeout int `json:"create_timeout"`
CreatedAt time.Time `json:"created_at"`
DiscoveryURL string `json:"discovery_url"`
DockerVolumeSize int `json:"docker_volume_size"`
Faults map[string]string `json:"faults"`
FlavorID string `json:"flavor_id"`
KeyPair string `json:"keypair"`
Labels map[string]string `json:"labels"`
Links []gophercloud.Link `json:"links"`
MasterFlavorID string `json:"master_flavor_id"`
MasterAddresses []string `json:"master_addresses"`
MasterCount int `json:"master_count"`
Name string `json:"name"`
NodeAddresses []string `json:"node_addresses"`
NodeCount int `json:"node_count"`
ProjectID string `json:"project_id"`
StackID string `json:"stack_id"`
Status string `json:"status"`
StatusReason string `json:"status_reason"`
UUID string `json:"uuid"`
UpdatedAt time.Time `json:"updated_at"`
UserID string `json:"user_id"`
FloatingIPEnabled bool `json:"floating_ip_enabled"`
FixedNetwork string `json:"fixed_network"`
FixedSubnet string `json:"fixed_subnet"`
HealthStatus string `json:"health_status"`
HealthStatusReason string `json:"health_status_reason"`
APIAddress string `json:"api_address"`
COEVersion string `json:"coe_version"`
ClusterTemplateID string `json:"cluster_template_id"`
ContainerVersion string `json:"container_version"`
CreateTimeout int `json:"create_timeout"`
CreatedAt time.Time `json:"created_at"`
DiscoveryURL string `json:"discovery_url"`
DockerVolumeSize int `json:"docker_volume_size"`
Faults map[string]string `json:"faults"`
FlavorID string `json:"flavor_id"`
KeyPair string `json:"keypair"`
Labels map[string]string `json:"labels"`
Links []gophercloud.Link `json:"links"`
MasterFlavorID string `json:"master_flavor_id"`
MasterAddresses []string `json:"master_addresses"`
MasterCount int `json:"master_count"`
Name string `json:"name"`
NodeAddresses []string `json:"node_addresses"`
NodeCount int `json:"node_count"`
ProjectID string `json:"project_id"`
StackID string `json:"stack_id"`
Status string `json:"status"`
StatusReason string `json:"status_reason"`
UUID string `json:"uuid"`
UpdatedAt time.Time `json:"updated_at"`
UserID string `json:"user_id"`
FloatingIPEnabled bool `json:"floating_ip_enabled"`
FixedNetwork string `json:"fixed_network"`
FixedSubnet string `json:"fixed_subnet"`
HealthStatus string `json:"health_status"`
HealthStatusReason map[string]interface{} `json:"health_status_reason"`
}
type ClusterPage struct {

View File

@@ -8,7 +8,7 @@ for more information.
Example to List Tenants
listOpts := tenants.ListOpts{
listOpts := &tenants.ListOpts{
Limit: 2,
}

View File

@@ -96,8 +96,8 @@ type Token struct {
OAuthToken string `q:"oauth_token"`
// OAuthTokenSecret is the secret value associated with the OAuth Token.
OAuthTokenSecret string `q:"oauth_token_secret"`
// OAUthExpiresAt is the date and time when an OAuth token expires.
OAUthExpiresAt *time.Time `q:"-"`
// OAuthExpiresAt is the date and time when an OAuth token expires.
OAuthExpiresAt *time.Time `q:"-"`
}
// TokenResult is a struct to handle
@@ -127,7 +127,7 @@ func (r TokenResult) Extract() (*Token, error) {
if t, err := time.Parse(gophercloud.RFC3339Milli, v); err != nil {
return nil, err
} else {
token.OAUthExpiresAt = &t
token.OAuthExpiresAt = &t
}
}

View File

@@ -94,10 +94,32 @@ type ProviderClient struct {
// reauthlock represents a set of attributes used to help in the reauthentication process.
type reauthlock struct {
sync.RWMutex
// This channel is non-nil during reauthentication. It can be used to ask the
// goroutine doing Reauthenticate() for its result. Look at the implementation
// of Reauthenticate() for details.
ongoing chan<- (chan<- error)
ongoing *reauthFuture
}
// reauthFuture represents future result of the reauthentication process.
// while done channel is not closed, reauthentication is in progress.
// when done channel is closed, err contains the result of reauthentication.
type reauthFuture struct {
done chan struct{}
err error
}
func newReauthFuture() *reauthFuture {
return &reauthFuture{
make(chan struct{}),
nil,
}
}
func (f *reauthFuture) Set(err error) {
f.err = err
close(f.done)
}
func (f *reauthFuture) Get() error {
<-f.done
return f.err
}
// AuthenticatedHeaders returns a map of HTTP headers that are common for all
@@ -112,9 +134,7 @@ func (client *ProviderClient) AuthenticatedHeaders() (m map[string]string) {
ongoing := client.reauthmut.ongoing
client.reauthmut.Unlock()
if ongoing != nil {
responseChannel := make(chan error)
ongoing <- responseChannel
_ = <-responseChannel
_ = ongoing.Get()
}
}
t := client.Token()
@@ -237,21 +257,19 @@ func (client *ProviderClient) Reauthenticate(previousToken string) error {
return client.ReauthFunc()
}
messages := make(chan (chan<- error))
future := newReauthFuture()
// Check if a Reauthenticate is in progress, or start one if not.
client.reauthmut.Lock()
ongoing := client.reauthmut.ongoing
if ongoing == nil {
client.reauthmut.ongoing = messages
client.reauthmut.ongoing = future
}
client.reauthmut.Unlock()
// If Reauthenticate is running elsewhere, wait for its result.
if ongoing != nil {
responseChannel := make(chan error)
ongoing <- responseChannel
return <-responseChannel
return ongoing.Get()
}
// Perform the actual reauthentication.
@@ -264,22 +282,10 @@ func (client *ProviderClient) Reauthenticate(previousToken string) error {
// Mark Reauthenticate as finished.
client.reauthmut.Lock()
client.reauthmut.ongoing.Set(err)
client.reauthmut.ongoing = nil
client.reauthmut.Unlock()
// Report result to all other interested goroutines.
//
// This happens in a separate goroutine because another goroutine might have
// acquired a copy of `client.reauthmut.ongoing` before we cleared it, but not
// have come around to sending its request. By answering in a goroutine, we
// can have that goroutine linger until all responseChannels have been sent.
// When GC has collected all sendings ends of the channel, our receiving end
// will be closed and the goroutine will end.
go func() {
for responseChannel := range messages {
responseChannel <- err
}
}()
return err
}

View File

@@ -4,11 +4,14 @@ import (
"context"
"fmt"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/baremetal/httpbasic"
"github.com/gophercloud/gophercloud/openstack/baremetal/noauth"
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/drivers"
httpbasicintrospection "github.com/gophercloud/gophercloud/openstack/baremetalintrospection/httpbasic"
noauthintrospection "github.com/gophercloud/gophercloud/openstack/baremetalintrospection/noauth"
"github.com/gophercloud/gophercloud/pagination"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"log"
"net/http"
@@ -60,7 +63,7 @@ func (c *Clients) GetIronicClient() (*gophercloud.ServiceClient, error) {
// We previously tried and it failed.
if c.ironicFailed {
return nil, fmt.Errorf("could not contact API: timeout reached")
return nil, fmt.Errorf("could not contact Ironic API: timeout reached")
}
// Let's poll the API until it's up, or times out.
@@ -82,7 +85,7 @@ func (c *Clients) GetIronicClient() (*gophercloud.ServiceClient, error) {
case <-ctx.Done():
if err := ctx.Err(); err != nil {
c.ironicFailed = true
return nil, fmt.Errorf("could not contact API: %w", err)
return nil, fmt.Errorf("could not contact Ironic API: %w", err)
}
case <-done:
}
@@ -104,7 +107,7 @@ func (c *Clients) GetInspectorClient() (*gophercloud.ServiceClient, error) {
} else if c.inspectorUp || c.timeout == 0 {
return c.inspector, nil
} else if c.inspectorFailed {
return nil, fmt.Errorf("could not contact API: timeout reached")
return nil, fmt.Errorf("could not contact Inspector API: timeout reached")
}
// Let's poll the API until it's up, or times out.
@@ -166,6 +169,41 @@ func Provider() terraform.ResourceProvider {
Description: descriptions["timeout"],
Default: 0,
},
"auth_strategy": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("IRONIC_AUTH_STRATEGY", "noauth"),
Description: descriptions["auth_strategy"],
ValidateFunc: validation.StringInSlice([]string{
"noauth", "http_basic",
}, false),
},
"ironic_username": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("IRONIC_HTTP_BASIC_USERNAME", ""),
Description: descriptions["ironic_username"],
},
"ironic_password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("IRONIC_HTTP_BASIC_PASSWORD", ""),
Description: descriptions["ironic_password"],
},
"inspector_username": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("INSPECTOR_HTTP_BASIC_USERNAME", ""),
Description: descriptions["inspector_username"],
},
"inspector_password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("INSPECTOR_HTTP_BASIC_PASSWORD", ""),
Description: descriptions["inspector_username"],
},
},
ResourcesMap: map[string]*schema.Resource{
"ironic_node_v1": resourceNodeV1(),
@@ -184,10 +222,15 @@ var descriptions map[string]string
func init() {
descriptions = map[string]string{
"url": "The authentication endpoint for Ironic",
"inspector": "The endpoint for Ironic inspector",
"microversion": "The microversion to use for Ironic",
"timeout": "Wait at least the specified number of seconds for the API to become available",
"url": "The authentication endpoint for Ironic",
"inspector": "The endpoint for Ironic inspector",
"microversion": "The microversion to use for Ironic",
"timeout": "Wait at least the specified number of seconds for the API to become available",
"auth_strategy": "Determine the strategy to use for authentication with Ironic services, Possible values: noauth, http_basic. Defaults to noauth.",
"ironic_username": "Username to be used by Ironic when using `http_basic` authentication",
"ironic_password": "Password to be used by Ironic when using `http_basic` authentication",
"inspector_username": "Username to be used by Ironic Inspector when using `http_basic` authentication",
"inspector_password": "Password to be used by Ironic Inspector when using `http_basic` authentication",
}
}
@@ -201,30 +244,72 @@ func configureProvider(schema *schema.ResourceData) (interface{}, error) {
}
log.Printf("[DEBUG] Ironic endpoint is %s", url)
ironic, err := noauth.NewBareMetalNoAuth(noauth.EndpointOpts{
IronicEndpoint: url,
})
if err != nil {
return nil, err
}
ironic.Microversion = schema.Get("microversion").(string)
clients.ironic = ironic
authStrategy := schema.Get("auth_strategy").(string)
inspectorURL := schema.Get("inspector").(string)
if inspectorURL != "" {
log.Printf("[DEBUG] Inspector endpoint is %s", inspectorURL)
inspector, err := noauthintrospection.NewBareMetalIntrospectionNoAuth(noauthintrospection.EndpointOpts{
IronicInspectorEndpoint: inspectorURL,
if authStrategy == "http_basic" {
log.Printf("[DEBUG] Using http_basic auth_strategy")
ironicUser := schema.Get("ironic_username").(string)
ironicPassword := schema.Get("ironic_password").(string)
ironic, err := httpbasic.NewBareMetalHTTPBasic(httpbasic.EndpointOpts{
IronicEndpoint: url,
IronicUser: ironicUser,
IronicUserPassword: ironicPassword,
})
if err != nil {
return nil, err
}
ironic.Microversion = schema.Get("microversion").(string)
clients.ironic = ironic
inspectorURL := schema.Get("inspector").(string)
if inspectorURL != "" {
inspectorUser := schema.Get("inspector_username").(string)
inspectorPassword := schema.Get("inspector_password").(string)
log.Printf("[DEBUG] Inspector endpoint is %s", inspectorURL)
inspector, err := httpbasicintrospection.NewBareMetalIntrospectionHTTPBasic(httpbasicintrospection.EndpointOpts{
IronicInspectorEndpoint: inspectorURL,
IronicInspectorUser: inspectorUser,
IronicInspectorUserPassword: inspectorPassword,
})
if err != nil {
return nil, err
}
clients.inspector = inspector
}
} else {
log.Printf("[DEBUG] Using noauth auth_strategy")
ironic, err := noauth.NewBareMetalNoAuth(noauth.EndpointOpts{
IronicEndpoint: url,
})
if err != nil {
return nil, fmt.Errorf("could not configure inspector endpoint: %s", err.Error())
return nil, err
}
clients.inspector = inspector
ironic.Microversion = schema.Get("microversion").(string)
clients.ironic = ironic
inspectorURL := schema.Get("inspector").(string)
if inspectorURL != "" {
log.Printf("[DEBUG] Inspector endpoint is %s", inspectorURL)
inspector, err := noauthintrospection.NewBareMetalIntrospectionNoAuth(noauthintrospection.EndpointOpts{
IronicInspectorEndpoint: inspectorURL,
})
if err != nil {
return nil, fmt.Errorf("could not configure inspector endpoint: %s", err.Error())
}
clients.inspector = inspector
}
}
clients.timeout = schema.Get("timeout").(int)
return &clients, err
return &clients, nil
}
// Retries an API forever until it responds.

7
vendor/modules.txt vendored
View File

@@ -521,16 +521,18 @@ github.com/googleapis/gax-go/v2
github.com/googleapis/gnostic/OpenAPIv2
github.com/googleapis/gnostic/compiler
github.com/googleapis/gnostic/extensions
# github.com/gophercloud/gophercloud v0.11.0
# github.com/gophercloud/gophercloud v0.12.0
## explicit
github.com/gophercloud/gophercloud
github.com/gophercloud/gophercloud/internal
github.com/gophercloud/gophercloud/openstack
github.com/gophercloud/gophercloud/openstack/baremetal/httpbasic
github.com/gophercloud/gophercloud/openstack/baremetal/noauth
github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations
github.com/gophercloud/gophercloud/openstack/baremetal/v1/drivers
github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes
github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports
github.com/gophercloud/gophercloud/openstack/baremetalintrospection/httpbasic
github.com/gophercloud/gophercloud/openstack/baremetalintrospection/noauth
github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection
github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/quotasets
@@ -997,9 +999,10 @@ github.com/oklog/run
# github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
## explicit
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
# github.com/openshift-metal3/terraform-provider-ironic v0.2.2
# github.com/openshift-metal3/terraform-provider-ironic v0.2.3
## explicit
github.com/openshift-metal3/terraform-provider-ironic/ironic
# github.com/openshift/api v3.9.1-0.20191111211345-a27ff30ebf09+incompatible => github.com/openshift/api v0.0.0-20200601094953-95abe2d2f422