github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/baremetal/v1/nodes/results.go (about)

     1  package nodes
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/vnpaycloud-console/gophercloud/v2"
     9  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/baremetal/inventory"
    10  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/baremetalintrospection/v1/introspection"
    11  	"github.com/vnpaycloud-console/gophercloud/v2/pagination"
    12  )
    13  
    14  type nodeResult struct {
    15  	gophercloud.Result
    16  }
    17  
    18  // Extract interprets any nodeResult as a Node, if possible.
    19  func (r nodeResult) Extract() (*Node, error) {
    20  	var s Node
    21  	err := r.ExtractInto(&s)
    22  	return &s, err
    23  }
    24  
    25  // Extract interprets a BootDeviceResult as BootDeviceOpts, if possible.
    26  func (r BootDeviceResult) Extract() (*BootDeviceOpts, error) {
    27  	var s BootDeviceOpts
    28  	err := r.ExtractInto(&s)
    29  	return &s, err
    30  }
    31  
    32  // Extract interprets a SupportedBootDeviceResult as an array of supported boot devices, if possible.
    33  func (r SupportedBootDeviceResult) Extract() ([]string, error) {
    34  	var s struct {
    35  		Devices []string `json:"supported_boot_devices"`
    36  	}
    37  
    38  	err := r.ExtractInto(&s)
    39  	return s.Devices, err
    40  }
    41  
    42  // Extract interprets a ValidateResult as NodeValidation, if possible.
    43  func (r ValidateResult) Extract() (*NodeValidation, error) {
    44  	var s NodeValidation
    45  	err := r.ExtractInto(&s)
    46  	return &s, err
    47  }
    48  
    49  func (r nodeResult) ExtractInto(v any) error {
    50  	return r.Result.ExtractIntoStructPtr(v, "")
    51  }
    52  
    53  func ExtractNodesInto(r pagination.Page, v any) error {
    54  	return r.(NodePage).Result.ExtractIntoSlicePtr(v, "nodes")
    55  }
    56  
    57  // Extract interprets a BIOSSettingsResult as an array of BIOSSetting structs, if possible.
    58  func (r ListBIOSSettingsResult) Extract() ([]BIOSSetting, error) {
    59  	var s struct {
    60  		Settings []BIOSSetting `json:"bios"`
    61  	}
    62  
    63  	err := r.ExtractInto(&s)
    64  	return s.Settings, err
    65  }
    66  
    67  // Extract interprets a SingleBIOSSettingResult as a BIOSSetting struct, if possible.
    68  func (r GetBIOSSettingResult) Extract() (*BIOSSetting, error) {
    69  	var s SingleBIOSSetting
    70  	err := r.ExtractInto(&s)
    71  	return &s.Setting, err
    72  }
    73  
    74  // Extract interprets a VendorPassthruMethod as
    75  func (r VendorPassthruMethodsResult) Extract() (*VendorPassthruMethods, error) {
    76  	var s VendorPassthruMethods
    77  	err := r.ExtractInto(&s)
    78  	return &s, err
    79  }
    80  
    81  func (r GetAllSubscriptionsVendorPassthruResult) Extract() (*GetAllSubscriptionsVendorPassthru, error) {
    82  	var s GetAllSubscriptionsVendorPassthru
    83  	err := r.ExtractInto(&s)
    84  	return &s, err
    85  }
    86  
    87  func (r SubscriptionVendorPassthruResult) Extract() (*SubscriptionVendorPassthru, error) {
    88  	var s SubscriptionVendorPassthru
    89  	err := r.ExtractInto(&s)
    90  	return &s, err
    91  }
    92  
    93  // Link represents a hyperlink and its relationship to the current resource.
    94  type Link struct {
    95  	// Href is the URL of the related resource.
    96  	Href string `json:"href"`
    97  
    98  	// Rel describes the relationship of the resource to the current
    99  	// context (e.g., "self", "bookmark").
   100  	Rel string `json:"rel"`
   101  }
   102  
   103  // Node represents a node in the OpenStack Bare Metal API.
   104  // https://docs.openstack.org/api-ref/baremetal/#list-nodes-detailed
   105  type Node struct {
   106  	// UUID for the resource.
   107  	UUID string `json:"uuid"`
   108  
   109  	// Identifier for the Node resource. May be undefined. Certain words are reserved.
   110  	Name string `json:"name"`
   111  
   112  	// Current power state of this Node. Usually, “power on” or “power off”, but may be “None”
   113  	// if Ironic is unable to determine the power state (eg, due to hardware failure).
   114  	PowerState string `json:"power_state"`
   115  
   116  	// A power state transition has been requested, this field represents the requested (ie, “target”)
   117  	// state either “power on”, “power off”, “rebooting”, “soft power off” or “soft rebooting”.
   118  	TargetPowerState string `json:"target_power_state"`
   119  
   120  	// Current provisioning state of this Node.
   121  	ProvisionState string `json:"provision_state"`
   122  
   123  	// A provisioning action has been requested, this field represents the requested (ie, “target”) state. Note
   124  	// that a Node may go through several states during its transition to this target state. For instance, when
   125  	// requesting an instance be deployed to an AVAILABLE Node, the Node may go through the following state
   126  	// change progression: AVAILABLE -> DEPLOYING -> DEPLOYWAIT -> DEPLOYING -> ACTIVE
   127  	TargetProvisionState string `json:"target_provision_state"`
   128  
   129  	// Whether or not this Node is currently in “maintenance mode”. Setting a Node into maintenance mode removes it
   130  	// from the available resource pool and halts some internal automation. This can happen manually (eg, via an API
   131  	// request) or automatically when Ironic detects a hardware fault that prevents communication with the machine.
   132  	Maintenance bool `json:"maintenance"`
   133  
   134  	// Description of the reason why this Node was placed into maintenance mode
   135  	MaintenanceReason string `json:"maintenance_reason"`
   136  
   137  	// Fault indicates the active fault detected by ironic, typically the Node is in “maintenance mode”. None means no
   138  	// fault has been detected by ironic. “power failure” indicates ironic failed to retrieve power state from this
   139  	// node. There are other possible types, e.g., “clean failure” and “rescue abort failure”.
   140  	Fault string `json:"fault"`
   141  
   142  	// Error from the most recent (last) transaction that started but failed to finish.
   143  	LastError string `json:"last_error"`
   144  
   145  	// Name of an Ironic Conductor host which is holding a lock on this node, if a lock is held. Usually “null”,
   146  	// but this field can be useful for debugging.
   147  	Reservation string `json:"reservation"`
   148  
   149  	// Name of the driver.
   150  	Driver string `json:"driver"`
   151  
   152  	// The metadata required by the driver to manage this Node. List of fields varies between drivers, and can be
   153  	// retrieved from the /v1/drivers/<DRIVER_NAME>/properties resource.
   154  	DriverInfo map[string]any `json:"driver_info"`
   155  
   156  	// Metadata set and stored by the Node’s driver. This field is read-only.
   157  	DriverInternalInfo map[string]any `json:"driver_internal_info"`
   158  
   159  	// Characteristics of this Node. Populated by ironic-inspector during inspection. May be edited via the REST
   160  	// API at any time.
   161  	Properties map[string]any `json:"properties"`
   162  
   163  	// Used to customize the deployed image. May include root partition size, a base 64 encoded config drive, and other
   164  	// metadata. Note that this field is erased automatically when the instance is deleted (this is done by requesting
   165  	// the Node provision state be changed to DELETED).
   166  	InstanceInfo map[string]any `json:"instance_info"`
   167  
   168  	// ID of the Nova instance associated with this Node.
   169  	InstanceUUID string `json:"instance_uuid"`
   170  
   171  	// ID of the chassis associated with this Node. May be empty or None.
   172  	ChassisUUID string `json:"chassis_uuid"`
   173  
   174  	// Set of one or more arbitrary metadata key and value pairs.
   175  	Extra map[string]any `json:"extra"`
   176  
   177  	// Whether console access is enabled or disabled on this node.
   178  	ConsoleEnabled bool `json:"console_enabled"`
   179  
   180  	// The current RAID configuration of the node. Introduced with the cleaning feature.
   181  	RAIDConfig map[string]any `json:"raid_config"`
   182  
   183  	// The requested RAID configuration of the node, which will be applied when the Node next transitions
   184  	// through the CLEANING state. Introduced with the cleaning feature.
   185  	TargetRAIDConfig map[string]any `json:"target_raid_config"`
   186  
   187  	// Current clean step. Introduced with the cleaning feature.
   188  	CleanStep map[string]any `json:"clean_step"`
   189  
   190  	// Current deploy step.
   191  	DeployStep map[string]any `json:"deploy_step"`
   192  
   193  	// A list of relative links. Includes the self and bookmark links.
   194  	Links []Link `json:"links"`
   195  
   196  	// Links to the collection of ports on this node
   197  	Ports []Link `json:"ports"`
   198  
   199  	// Links to the collection of portgroups on this node.
   200  	PortGroups []Link `json:"portgroups"`
   201  
   202  	// Links to the collection of states. Note that this resource is also used to request state transitions.
   203  	States []Link `json:"states"`
   204  
   205  	// String which can be used by external schedulers to identify this Node as a unit of a specific type of resource.
   206  	// For more details, see: https://docs.openstack.org/ironic/latest/install/configure-nova-flavors.html
   207  	ResourceClass string `json:"resource_class"`
   208  
   209  	// BIOS interface for a Node, e.g. “redfish”.
   210  	BIOSInterface string `json:"bios_interface"`
   211  
   212  	// Boot interface for a Node, e.g. “pxe”.
   213  	BootInterface string `json:"boot_interface"`
   214  
   215  	// Console interface for a node, e.g. “no-console”.
   216  	ConsoleInterface string `json:"console_interface"`
   217  
   218  	// Deploy interface for a node, e.g. “iscsi”.
   219  	DeployInterface string `json:"deploy_interface"`
   220  
   221  	// Interface used for node inspection, e.g. “no-inspect”.
   222  	InspectInterface string `json:"inspect_interface"`
   223  
   224  	// For out-of-band node management, e.g. “ipmitool”.
   225  	ManagementInterface string `json:"management_interface"`
   226  
   227  	// Network Interface provider to use when plumbing the network connections for this Node.
   228  	NetworkInterface string `json:"network_interface"`
   229  
   230  	// used for performing power actions on the node, e.g. “ipmitool”.
   231  	PowerInterface string `json:"power_interface"`
   232  
   233  	// Used for configuring RAID on this node, e.g. “no-raid”.
   234  	RAIDInterface string `json:"raid_interface"`
   235  
   236  	// Interface used for node rescue, e.g. “no-rescue”.
   237  	RescueInterface string `json:"rescue_interface"`
   238  
   239  	// Used for attaching and detaching volumes on this node, e.g. “cinder”.
   240  	StorageInterface string `json:"storage_interface"`
   241  
   242  	// Array of traits for this node.
   243  	Traits []string `json:"traits"`
   244  
   245  	// For vendor-specific functionality on this node, e.g. “no-vendor”.
   246  	VendorInterface string `json:"vendor_interface"`
   247  
   248  	// Links to the volume resources.
   249  	Volume []Link `json:"volume"`
   250  
   251  	// Conductor group for a node. Case-insensitive string up to 255 characters, containing a-z, 0-9, _, -, and ..
   252  	ConductorGroup string `json:"conductor_group"`
   253  
   254  	// An optional UUID which can be used to denote the “parent” baremetal node.
   255  	ParentNode string `json:"parent_node"`
   256  
   257  	// The node is protected from undeploying, rebuilding and deletion.
   258  	Protected bool `json:"protected"`
   259  
   260  	// Reason the node is marked as protected.
   261  	ProtectedReason string `json:"protected_reason"`
   262  
   263  	// A string or UUID of the tenant who owns the baremetal node.
   264  	Owner string `json:"owner"`
   265  
   266  	// A string or UUID of the tenant who is leasing the object.
   267  	Lessee string `json:"lessee"`
   268  
   269  	// A string indicating the shard this node belongs to.
   270  	Shard string `json:"shard"`
   271  
   272  	// Informational text about this node.
   273  	Description string `json:"description"`
   274  
   275  	// The conductor currently servicing a node. This field is read-only.
   276  	Conductor string `json:"conductor"`
   277  
   278  	// The UUID of the allocation associated with the node. If not null, will be the same as instance_uuid
   279  	// (the opposite is not always true). Unlike instance_uuid, this field is read-only. Please use the
   280  	// Allocation API to remove allocations.
   281  	AllocationUUID string `json:"allocation_uuid"`
   282  
   283  	// Whether the node is retired. A Node tagged as retired will prevent any further
   284  	// scheduling of instances, but will still allow for other operations, such as cleaning, to happen
   285  	Retired bool `json:"retired"`
   286  
   287  	// Reason the node is marked as retired.
   288  	RetiredReason string `json:"retired_reason"`
   289  
   290  	// Static network configuration to use during deployment and cleaning.
   291  	NetworkData map[string]any `json:"network_data"`
   292  
   293  	// Whether automated cleaning is enabled or disabled on this node.
   294  	// Requires microversion 1.47 or later.
   295  	AutomatedClean *bool `json:"automated_clean"`
   296  
   297  	// Current service step.
   298  	ServiceStep map[string]any `json:"service_step"`
   299  
   300  	// Firmware interface for a node, e.g. “redfish”.
   301  	FirmwareInterface string `json:"firmware_interface"`
   302  
   303  	// The UTC date and time when the provision state was updated, ISO 8601 format. May be “null”.
   304  	ProvisionUpdatedAt time.Time `json:"provision_updated_at"`
   305  
   306  	// The UTC date and time when the last inspection was started, ISO 8601 format. May be “null” if inspection hasn't been started yet.
   307  	InspectionStartedAt *time.Time `json:"inspection_started_at"`
   308  
   309  	// The UTC date and time when the last inspection was finished, ISO 8601 format. May be “null” if inspection hasn't been finished yet.
   310  	InspectionFinishedAt *time.Time `json:"inspection_finished_at"`
   311  
   312  	// The UTC date and time when the resource was created, ISO 8601 format.
   313  	CreatedAt time.Time `json:"created_at"`
   314  
   315  	// The UTC date and time when the resource was updated, ISO 8601 format. May be “null”.
   316  	UpdatedAt time.Time `json:"updated_at"`
   317  
   318  	// Whether disable_power_off is enabled or disabled on this node.
   319  	// Requires microversion 1.95 or later.
   320  	DisablePowerOff bool `json:"disable_power_off"`
   321  }
   322  
   323  // NodePage abstracts the raw results of making a List() request against
   324  // the API. As OpenStack extensions may freely alter the response bodies of
   325  // structures returned to the client, you may only safely access the data
   326  // provided through the ExtractNodes call.
   327  type NodePage struct {
   328  	pagination.LinkedPageBase
   329  }
   330  
   331  // IsEmpty returns true if a page contains no Node results.
   332  func (r NodePage) IsEmpty() (bool, error) {
   333  	if r.StatusCode == 204 {
   334  		return true, nil
   335  	}
   336  
   337  	s, err := ExtractNodes(r)
   338  	return len(s) == 0, err
   339  }
   340  
   341  // NextPageURL uses the response's embedded link reference to navigate to the
   342  // next page of results.
   343  func (r NodePage) NextPageURL() (string, error) {
   344  	var s struct {
   345  		Links []gophercloud.Link `json:"nodes_links"`
   346  	}
   347  	err := r.ExtractInto(&s)
   348  	if err != nil {
   349  		return "", err
   350  	}
   351  	return gophercloud.ExtractNextURL(s.Links)
   352  }
   353  
   354  // ExtractNodes interprets the results of a single page from a List() call,
   355  // producing a slice of Node entities.
   356  func ExtractNodes(r pagination.Page) ([]Node, error) {
   357  	var s []Node
   358  	err := ExtractNodesInto(r, &s)
   359  	return s, err
   360  }
   361  
   362  // GetResult is the response from a Get operation. Call its Extract
   363  // method to interpret it as a Node.
   364  type GetResult struct {
   365  	nodeResult
   366  }
   367  
   368  // CreateResult is the response from a Create operation.
   369  type CreateResult struct {
   370  	nodeResult
   371  }
   372  
   373  // UpdateResult is the response from an Update operation. Call its Extract
   374  // method to interpret it as a Node.
   375  type UpdateResult struct {
   376  	nodeResult
   377  }
   378  
   379  // DeleteResult is the response from a Delete operation. Call its ExtractErr
   380  // method to determine if the call succeeded or failed.
   381  type DeleteResult struct {
   382  	gophercloud.ErrResult
   383  }
   384  
   385  // ValidateResult is the response from a Validate operation. Call its Extract
   386  // method to interpret it as a NodeValidation struct.
   387  type ValidateResult struct {
   388  	gophercloud.Result
   389  }
   390  
   391  // InjectNMIResult is the response from an InjectNMI operation. Call its ExtractErr
   392  // method to determine if the call succeeded or failed.
   393  type InjectNMIResult struct {
   394  	gophercloud.ErrResult
   395  }
   396  
   397  // BootDeviceResult is the response from a GetBootDevice operation. Call its Extract
   398  // method to interpret it as a BootDeviceOpts struct.
   399  type BootDeviceResult struct {
   400  	gophercloud.Result
   401  }
   402  
   403  // SetBootDeviceResult is the response from a SetBootDevice operation. Call its Extract
   404  // method to interpret it as a BootDeviceOpts struct.
   405  type SetBootDeviceResult struct {
   406  	gophercloud.ErrResult
   407  }
   408  
   409  // SupportedBootDeviceResult is the response from a GetSupportedBootDevices operation. Call its Extract
   410  // method to interpret it as an array of supported boot device values.
   411  type SupportedBootDeviceResult struct {
   412  	gophercloud.Result
   413  }
   414  
   415  // ChangePowerStateResult is the response from a ChangePowerState operation. Call its ExtractErr
   416  // method to determine if the call succeeded or failed.
   417  type ChangePowerStateResult struct {
   418  	gophercloud.ErrResult
   419  }
   420  
   421  // ListBIOSSettingsResult is the response from a ListBIOSSettings operation. Call its Extract
   422  // method to interpret it as an array of BIOSSetting structs.
   423  type ListBIOSSettingsResult struct {
   424  	gophercloud.Result
   425  }
   426  
   427  // GetBIOSSettingResult is the response from a GetBIOSSetting operation. Call its Extract
   428  // method to interpret it as a BIOSSetting struct.
   429  type GetBIOSSettingResult struct {
   430  	gophercloud.Result
   431  }
   432  
   433  // VendorPassthruMethodsResult is the response from a GetVendorPassthruMethods operation. Call its Extract
   434  // method to interpret it as an array of allowed vendor methods.
   435  type VendorPassthruMethodsResult struct {
   436  	gophercloud.Result
   437  }
   438  
   439  // GetAllSubscriptionsVendorPassthruResult is the response from GetAllSubscriptions operation. Call its
   440  // Extract method to interpret it as a GetAllSubscriptionsVendorPassthru struct.
   441  type GetAllSubscriptionsVendorPassthruResult struct {
   442  	gophercloud.Result
   443  }
   444  
   445  // SubscriptionVendorPassthruResult is the response from GetSubscription and CreateSubscription operation. Call its Extract
   446  // method to interpret it as a SubscriptionVendorPassthru struct.
   447  type SubscriptionVendorPassthruResult struct {
   448  	gophercloud.Result
   449  }
   450  
   451  // DeleteSubscriptionVendorPassthruResult is the response from DeleteSubscription operation. Call its
   452  // ExtractErr method to determine if the call succeeded of failed.
   453  type DeleteSubscriptionVendorPassthruResult struct {
   454  	gophercloud.ErrResult
   455  }
   456  
   457  // Each element in the response will contain a “result” variable, which will have a value of “true” or “false”, and
   458  // also potentially a reason. A value of nil indicates that the Node’s driver does not support that interface.
   459  type DriverValidation struct {
   460  	Result bool   `json:"result"`
   461  	Reason string `json:"reason"`
   462  }
   463  
   464  // Ironic validates whether the Node’s driver has enough information to manage the Node. This polls each interface on
   465  // the driver, and returns the status of that interface as an DriverValidation struct.
   466  type NodeValidation struct {
   467  	BIOS       DriverValidation `json:"bios"`
   468  	Boot       DriverValidation `json:"boot"`
   469  	Console    DriverValidation `json:"console"`
   470  	Deploy     DriverValidation `json:"deploy"`
   471  	Firmware   DriverValidation `json:"firmware"`
   472  	Inspect    DriverValidation `json:"inspect"`
   473  	Management DriverValidation `json:"management"`
   474  	Network    DriverValidation `json:"network"`
   475  	Power      DriverValidation `json:"power"`
   476  	RAID       DriverValidation `json:"raid"`
   477  	Rescue     DriverValidation `json:"rescue"`
   478  	Storage    DriverValidation `json:"storage"`
   479  }
   480  
   481  // A particular BIOS setting for a node in the OpenStack Bare Metal API.
   482  type BIOSSetting struct {
   483  
   484  	// Identifier for the BIOS setting.
   485  	Name string `json:"name"`
   486  
   487  	// Value of the BIOS setting.
   488  	Value string `json:"value"`
   489  
   490  	// The following fields are returned in microversion 1.74 or later
   491  	// when using the `details` option
   492  
   493  	// The type of setting - Enumeration, String, Integer, or Boolean.
   494  	AttributeType string `json:"attribute_type"`
   495  
   496  	// The allowable value for an Enumeration type setting.
   497  	AllowableValues []string `json:"allowable_values"`
   498  
   499  	// The lowest value for an Integer type setting.
   500  	LowerBound *int `json:"lower_bound"`
   501  
   502  	// The highest value for an Integer type setting.
   503  	UpperBound *int `json:"upper_bound"`
   504  
   505  	// Minimum length for a String type setting.
   506  	MinLength *int `json:"min_length"`
   507  
   508  	// Maximum length for a String type setting.
   509  	MaxLength *int `json:"max_length"`
   510  
   511  	// Whether or not this setting is read only.
   512  	ReadOnly *bool `json:"read_only"`
   513  
   514  	// Whether or not a reset is required after changing this setting.
   515  	ResetRequired *bool `json:"reset_required"`
   516  
   517  	// Whether or not this setting's value is unique to this node, e.g.
   518  	// a serial number.
   519  	Unique *bool `json:"unique"`
   520  }
   521  
   522  type SingleBIOSSetting struct {
   523  	Setting BIOSSetting
   524  }
   525  
   526  // ChangeStateResult is the response from any state change operation. Call its ExtractErr
   527  // method to determine if the call succeeded or failed.
   528  type ChangeStateResult struct {
   529  	gophercloud.ErrResult
   530  }
   531  
   532  type VendorPassthruMethods struct {
   533  	CreateSubscription  CreateSubscriptionMethod  `json:"create_subscription,omitempty"`
   534  	DeleteSubscription  DeleteSubscriptionMethod  `json:"delete_subscription,omitempty"`
   535  	GetSubscription     GetSubscriptionMethod     `json:"get_subscription,omitempty"`
   536  	GetAllSubscriptions GetAllSubscriptionsMethod `json:"get_all_subscriptions,omitempty"`
   537  }
   538  
   539  // Below you can find all vendor passthru methods structs
   540  
   541  type CreateSubscriptionMethod struct {
   542  	HTTPMethods          []string `json:"http_methods"`
   543  	Async                bool     `json:"async"`
   544  	Description          string   `json:"description"`
   545  	Attach               bool     `json:"attach"`
   546  	RequireExclusiveLock bool     `json:"require_exclusive_lock"`
   547  }
   548  
   549  type DeleteSubscriptionMethod struct {
   550  	HTTPMethods          []string `json:"http_methods"`
   551  	Async                bool     `json:"async"`
   552  	Description          string   `json:"description"`
   553  	Attach               bool     `json:"attach"`
   554  	RequireExclusiveLock bool     `json:"require_exclusive_lock"`
   555  }
   556  
   557  type GetSubscriptionMethod struct {
   558  	HTTPMethods          []string `json:"http_methods"`
   559  	Async                bool     `json:"async"`
   560  	Description          string   `json:"description"`
   561  	Attach               bool     `json:"attach"`
   562  	RequireExclusiveLock bool     `json:"require_exclusive_lock"`
   563  }
   564  
   565  type GetAllSubscriptionsMethod struct {
   566  	HTTPMethods          []string `json:"http_methods"`
   567  	Async                bool     `json:"async"`
   568  	Description          string   `json:"description"`
   569  	Attach               bool     `json:"attach"`
   570  	RequireExclusiveLock bool     `json:"require_exclusive_lock"`
   571  }
   572  
   573  // A List of subscriptions from a node in the OpenStack Bare Metal API.
   574  type GetAllSubscriptionsVendorPassthru struct {
   575  	Context      string              `json:"@odata.context"`
   576  	Etag         string              `json:"@odata.etag"`
   577  	Id           string              `json:"@odata.id"`
   578  	Type         string              `json:"@odata.type"`
   579  	Description  string              `json:"Description"`
   580  	Name         string              `json:"Name"`
   581  	Members      []map[string]string `json:"Members"`
   582  	MembersCount int                 `json:"Members@odata.count"`
   583  }
   584  
   585  // A Subscription from a node in the OpenStack Bare Metal API.
   586  type SubscriptionVendorPassthru struct {
   587  	Id          string   `json:"Id"`
   588  	Context     string   `json:"Context"`
   589  	Destination string   `json:"Destination"`
   590  	EventTypes  []string `json:"EventTypes"`
   591  	Protocol    string   `json:"Protocol"`
   592  }
   593  
   594  // SetMaintenanceResult is the response from a SetMaintenance operation. Call its ExtractErr
   595  // method to determine if the call succeeded or failed.
   596  type SetMaintenanceResult struct {
   597  	gophercloud.ErrResult
   598  }
   599  
   600  // PluginData is an abstraction around plugin-specific data from inspection.
   601  // The format of PluginData is different between ironic-inspector and the native in-band inspection in Ironic.
   602  // We may need an opaque structure that can be extracted in two (or more) ways.
   603  type PluginData struct {
   604  	// Raw JSON data.
   605  	json.RawMessage
   606  }
   607  
   608  // Interpret plugin data as a free-form mapping.
   609  func (pd PluginData) AsMap() (result map[string]any, err error) {
   610  	err = json.Unmarshal(pd.RawMessage, &result)
   611  	return
   612  }
   613  
   614  // AsStandardData interprets plugin data as coming from ironic native inspection.
   615  func (pd PluginData) AsStandardData() (result inventory.StandardPluginData, err error) {
   616  	err = json.Unmarshal(pd.RawMessage, &result)
   617  	return
   618  }
   619  
   620  // AsInspectorData interprets plugin data as coming from ironic-inspector.
   621  func (pd PluginData) AsInspectorData() (result introspection.Data, err error) {
   622  	err = json.Unmarshal(pd.RawMessage, &result)
   623  	return
   624  }
   625  
   626  // GuessFormat tries to guess which format the data is in. Unless there is
   627  // an error while parsing, one result will be valid, the other - nil.
   628  // Unknown (but still parseable) format defaults to standard.
   629  func (pd PluginData) GuessFormat() (*inventory.StandardPluginData, *introspection.Data, error) {
   630  	// Ironic and Inspector formats are compatible, don't expect an error in either case
   631  	ironic, err := pd.AsStandardData()
   632  	if err != nil {
   633  		return nil, nil, err
   634  	}
   635  
   636  	// The valid_interfaces field only exists in the Ironic data (it's called just interfaces in Inspector)
   637  	if len(ironic.ValidInterfaces) > 0 {
   638  		return &ironic, nil, nil
   639  	}
   640  
   641  	inspector, err := pd.AsInspectorData()
   642  	if err != nil {
   643  		return nil, nil, fmt.Errorf("cannot interpret PluginData as coming from inspector on conversion: %w", err)
   644  	}
   645  
   646  	// If the format does not match anything (but still parses), assume a heavily customized deployment
   647  	if len(inspector.Interfaces) == 0 {
   648  		return &ironic, nil, nil
   649  	}
   650  
   651  	return nil, &inspector, nil
   652  }
   653  
   654  // InventoryData is the full node inventory.
   655  type InventoryData struct {
   656  	// Formally specified bare metal node inventory.
   657  	Inventory inventory.InventoryType `json:"inventory"`
   658  	// Data from inspection plugins.
   659  	PluginData PluginData `json:"plugin_data"`
   660  }
   661  
   662  // InventoryResult is the response from a GetInventory operation.
   663  type InventoryResult struct {
   664  	gophercloud.Result
   665  }
   666  
   667  // Extract interprets a InventoryResult as a InventoryData struct, if possible.
   668  func (r InventoryResult) Extract() (*InventoryData, error) {
   669  	var data InventoryData
   670  	err := r.ExtractInto(&data)
   671  	return &data, err
   672  }
   673  
   674  // ListFirmwareResult is the response from a ListFirmware operation. Call its Extract method
   675  // to interpret it as an array of FirmwareComponent structs.
   676  type ListFirmwareResult struct {
   677  	gophercloud.Result
   678  }
   679  
   680  // A particular Firmware Component for a node
   681  type FirmwareComponent struct {
   682  	// The UTC date and time when the resource was created, ISO 8601 format.
   683  	CreatedAt time.Time `json:"created_at"`
   684  	// The UTC date and time when the resource was updated, ISO 8601 format. May be “null”.
   685  	UpdatedAt *time.Time `json:"updated_at"`
   686  	// The Component name
   687  	Component string `json:"component"`
   688  	// The initial version of the firmware component.
   689  	InitialVersion string `json:"initial_version"`
   690  	// The current version of the firmware component.
   691  	CurrentVersion string `json:"current_version"`
   692  	// The last firmware version updated for the component.
   693  	LastVersionFlashed string `json:"last_version_flashed,omitempty"`
   694  }
   695  
   696  // Extract interprets a ListFirmwareResult as an array of FirmwareComponent structs, if possible.
   697  func (r ListFirmwareResult) Extract() ([]FirmwareComponent, error) {
   698  	var s struct {
   699  		Components []FirmwareComponent `json:"firmware"`
   700  	}
   701  
   702  	err := r.ExtractInto(&s)
   703  	return s.Components, err
   704  }
   705  
   706  type VirtualMediaAttachResult struct {
   707  	gophercloud.ErrResult
   708  }
   709  
   710  type VirtualMediaDetachResult struct {
   711  	gophercloud.ErrResult
   712  }