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

     1  package nodes
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/vnpaycloud-console/gophercloud/v2"
     8  	"github.com/vnpaycloud-console/gophercloud/v2/pagination"
     9  )
    10  
    11  // ListOptsBuilder allows extensions to add additional parameters to the
    12  // List request.
    13  type ListOptsBuilder interface {
    14  	ToNodeListQuery() (string, error)
    15  	ToNodeListDetailQuery() (string, error)
    16  }
    17  
    18  // Provision state reports the current provision state of the node, these are only used in filtering
    19  type ProvisionState string
    20  
    21  const (
    22  	Enroll       ProvisionState = "enroll"
    23  	Verifying    ProvisionState = "verifying"
    24  	Manageable   ProvisionState = "manageable"
    25  	Available    ProvisionState = "available"
    26  	Active       ProvisionState = "active"
    27  	DeployWait   ProvisionState = "wait call-back"
    28  	Deploying    ProvisionState = "deploying"
    29  	DeployFail   ProvisionState = "deploy failed"
    30  	DeployDone   ProvisionState = "deploy complete"
    31  	DeployHold   ProvisionState = "deploy hold"
    32  	Deleting     ProvisionState = "deleting"
    33  	Deleted      ProvisionState = "deleted"
    34  	Cleaning     ProvisionState = "cleaning"
    35  	CleanWait    ProvisionState = "clean wait"
    36  	CleanFail    ProvisionState = "clean failed"
    37  	CleanHold    ProvisionState = "clean hold"
    38  	Error        ProvisionState = "error"
    39  	Rebuild      ProvisionState = "rebuild"
    40  	Inspecting   ProvisionState = "inspecting"
    41  	InspectFail  ProvisionState = "inspect failed"
    42  	InspectWait  ProvisionState = "inspect wait"
    43  	Adopting     ProvisionState = "adopting"
    44  	AdoptFail    ProvisionState = "adopt failed"
    45  	Rescue       ProvisionState = "rescue"
    46  	RescueFail   ProvisionState = "rescue failed"
    47  	Rescuing     ProvisionState = "rescuing"
    48  	UnrescueFail ProvisionState = "unrescue failed"
    49  	RescueWait   ProvisionState = "rescue wait"
    50  	Unrescuing   ProvisionState = "unrescuing"
    51  	Servicing    ProvisionState = "servicing"
    52  	ServiceWait  ProvisionState = "service wait"
    53  	ServiceFail  ProvisionState = "service failed"
    54  	ServiceHold  ProvisionState = "service hold"
    55  )
    56  
    57  // TargetProvisionState is used when setting the provision state for a node.
    58  type TargetProvisionState string
    59  
    60  const (
    61  	TargetActive   TargetProvisionState = "active"
    62  	TargetDeleted  TargetProvisionState = "deleted"
    63  	TargetManage   TargetProvisionState = "manage"
    64  	TargetProvide  TargetProvisionState = "provide"
    65  	TargetInspect  TargetProvisionState = "inspect"
    66  	TargetAbort    TargetProvisionState = "abort"
    67  	TargetClean    TargetProvisionState = "clean"
    68  	TargetAdopt    TargetProvisionState = "adopt"
    69  	TargetRescue   TargetProvisionState = "rescue"
    70  	TargetUnrescue TargetProvisionState = "unrescue"
    71  	TargetRebuild  TargetProvisionState = "rebuild"
    72  	TargetService  TargetProvisionState = "service"
    73  	TargetUnhold   TargetProvisionState = "unhold"
    74  )
    75  
    76  const (
    77  	StepHold     string = "hold"
    78  	StepWait     string = "wait"
    79  	StepPowerOn  string = "power_on"
    80  	StepPowerOff string = "power_off"
    81  	StepReboot   string = "reboot"
    82  )
    83  
    84  // ListOpts allows the filtering and sorting of paginated collections through
    85  // the API. Filtering is achieved by passing in struct field values that map to
    86  // the node attributes you want to see returned. Marker and Limit are used
    87  // for pagination.
    88  type ListOpts struct {
    89  	// Filter the list by specific instance UUID
    90  	InstanceUUID string `q:"instance_uuid"`
    91  
    92  	// Filter the list by chassis UUID
    93  	ChassisUUID string `q:"chassis_uuid"`
    94  
    95  	// Filter the list by maintenance set to True or False
    96  	Maintenance bool `q:"maintenance"`
    97  
    98  	// Nodes which are, or are not, associated with an instance_uuid.
    99  	Associated bool `q:"associated"`
   100  
   101  	// Only return those with the specified provision_state.
   102  	ProvisionState ProvisionState `q:"provision_state"`
   103  
   104  	// Filter the list with the specified driver.
   105  	Driver string `q:"driver"`
   106  
   107  	// Filter the list with the specified resource class.
   108  	ResourceClass string `q:"resource_class"`
   109  
   110  	// Filter the list with the specified conductor_group.
   111  	ConductorGroup string `q:"conductor_group"`
   112  
   113  	// Filter the list with the specified fault.
   114  	Fault string `q:"fault"`
   115  
   116  	// One or more fields to be returned in the response.
   117  	Fields []string `q:"fields" format:"comma-separated"`
   118  
   119  	// Requests a page size of items.
   120  	Limit int `q:"limit"`
   121  
   122  	// The ID of the last-seen item.
   123  	Marker string `q:"marker"`
   124  
   125  	// Sorts the response by the requested sort direction.
   126  	SortDir string `q:"sort_dir"`
   127  
   128  	// Sorts the response by the this attribute value.
   129  	SortKey string `q:"sort_key"`
   130  
   131  	// A string or UUID of the tenant who owns the baremetal node.
   132  	Owner string `q:"owner"`
   133  }
   134  
   135  // ToNodeListQuery formats a ListOpts into a query string.
   136  func (opts ListOpts) ToNodeListQuery() (string, error) {
   137  	q, err := gophercloud.BuildQueryString(opts)
   138  	return q.String(), err
   139  }
   140  
   141  // List makes a request against the API to list nodes accessible to you.
   142  func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
   143  	url := listURL(client)
   144  	if opts != nil {
   145  		query, err := opts.ToNodeListQuery()
   146  		if err != nil {
   147  			return pagination.Pager{Err: err}
   148  		}
   149  		url += query
   150  	}
   151  	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
   152  		return NodePage{pagination.LinkedPageBase{PageResult: r}}
   153  	})
   154  }
   155  
   156  // ToNodeListDetailQuery formats a ListOpts into a query string for the list details API.
   157  func (opts ListOpts) ToNodeListDetailQuery() (string, error) {
   158  	// Detail endpoint can't filter by Fields
   159  	if len(opts.Fields) > 0 {
   160  		return "", fmt.Errorf("fields is not a valid option when getting a detailed listing of nodes")
   161  	}
   162  
   163  	q, err := gophercloud.BuildQueryString(opts)
   164  	return q.String(), err
   165  }
   166  
   167  // Return a list of bare metal Nodes with complete details. Some filtering is possible by passing in flags in ListOpts,
   168  // but you cannot limit by the fields returned.
   169  func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
   170  	// This URL is deprecated. In the future, we should compare the microversion and if >= 1.43, hit the listURL
   171  	// with ListOpts{Detail: true,}
   172  	url := listDetailURL(client)
   173  	if opts != nil {
   174  		query, err := opts.ToNodeListDetailQuery()
   175  		if err != nil {
   176  			return pagination.Pager{Err: err}
   177  		}
   178  		url += query
   179  	}
   180  	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
   181  		return NodePage{pagination.LinkedPageBase{PageResult: r}}
   182  	})
   183  }
   184  
   185  // Get requests details on a single node, by ID.
   186  func Get(ctx context.Context, client *gophercloud.ServiceClient, id string) (r GetResult) {
   187  	resp, err := client.Get(ctx, getURL(client, id), &r.Body, &gophercloud.RequestOpts{
   188  		OkCodes: []int{200},
   189  	})
   190  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   191  	return
   192  }
   193  
   194  // CreateOptsBuilder allows extensions to add additional parameters to the
   195  // Create request.
   196  type CreateOptsBuilder interface {
   197  	ToNodeCreateMap() (map[string]any, error)
   198  }
   199  
   200  // CreateOpts specifies node creation parameters.
   201  type CreateOpts struct {
   202  	// The interface to configure automated cleaning for a Node.
   203  	// Requires microversion 1.47 or later.
   204  	AutomatedClean *bool `json:"automated_clean,omitempty"`
   205  
   206  	// The BIOS interface for a Node, e.g. “redfish”.
   207  	BIOSInterface string `json:"bios_interface,omitempty"`
   208  
   209  	// The boot interface for a Node, e.g. “pxe”.
   210  	BootInterface string `json:"boot_interface,omitempty"`
   211  
   212  	// The conductor group for a node. Case-insensitive string up to 255 characters, containing a-z, 0-9, _, -, and ..
   213  	ConductorGroup string `json:"conductor_group,omitempty"`
   214  
   215  	// The console interface for a node, e.g. “no-console”.
   216  	ConsoleInterface string `json:"console_interface,omitempty"`
   217  
   218  	// The deploy interface for a node, e.g. “iscsi”.
   219  	DeployInterface string `json:"deploy_interface,omitempty"`
   220  
   221  	// All the metadata required by the driver to manage this Node. List of fields varies between drivers, and can
   222  	// be retrieved from the /v1/drivers/<DRIVER_NAME>/properties resource.
   223  	DriverInfo map[string]any `json:"driver_info,omitempty"`
   224  
   225  	// name of the driver used to manage this Node.
   226  	Driver string `json:"driver,omitempty"`
   227  
   228  	// A set of one or more arbitrary metadata key and value pairs.
   229  	Extra map[string]any `json:"extra,omitempty"`
   230  
   231  	// The firmware interface for a node, e.g. "redfish"
   232  	FirmwareInterface string `json:"firmware_interface,omitempty"`
   233  
   234  	// The interface used for node inspection, e.g. “no-inspect”.
   235  	InspectInterface string `json:"inspect_interface,omitempty"`
   236  
   237  	// Interface for out-of-band node management, e.g. “ipmitool”.
   238  	ManagementInterface string `json:"management_interface,omitempty"`
   239  
   240  	// Human-readable identifier for the Node resource. May be undefined. Certain words are reserved.
   241  	Name string `json:"name,omitempty"`
   242  
   243  	// Which Network Interface provider to use when plumbing the network connections for this Node.
   244  	NetworkInterface string `json:"network_interface,omitempty"`
   245  
   246  	// Interface used for performing power actions on the node, e.g. “ipmitool”.
   247  	PowerInterface string `json:"power_interface,omitempty"`
   248  
   249  	// Physical characteristics of this Node. Populated during inspection, if performed. Can be edited via the REST
   250  	// API at any time.
   251  	Properties map[string]any `json:"properties,omitempty"`
   252  
   253  	// Interface used for configuring RAID on this node, e.g. “no-raid”.
   254  	RAIDInterface string `json:"raid_interface,omitempty"`
   255  
   256  	// The interface used for node rescue, e.g. “no-rescue”.
   257  	RescueInterface string `json:"rescue_interface,omitempty"`
   258  
   259  	// A string which can be used by external schedulers to identify this Node as a unit of a specific type
   260  	// of resource.
   261  	ResourceClass string `json:"resource_class,omitempty"`
   262  
   263  	// Interface used for attaching and detaching volumes on this node, e.g. “cinder”.
   264  	StorageInterface string `json:"storage_interface,omitempty"`
   265  
   266  	// The UUID for the resource.
   267  	UUID string `json:"uuid,omitempty"`
   268  
   269  	// Interface for vendor-specific functionality on this node, e.g. “no-vendor”.
   270  	VendorInterface string `json:"vendor_interface,omitempty"`
   271  
   272  	// A string or UUID of the tenant who owns the baremetal node.
   273  	Owner string `json:"owner,omitempty"`
   274  
   275  	// Static network configuration to use during deployment and cleaning.
   276  	NetworkData map[string]any `json:"network_data,omitempty"`
   277  
   278  	// Whether disable_power_off is enabled or disabled on this node.
   279  	// Requires microversion 1.95 or later.
   280  	DisablePowerOff *bool `json:"disable_power_off,omitempty"`
   281  }
   282  
   283  // ToNodeCreateMap assembles a request body based on the contents of a CreateOpts.
   284  func (opts CreateOpts) ToNodeCreateMap() (map[string]any, error) {
   285  	body, err := gophercloud.BuildRequestBody(opts, "")
   286  	if err != nil {
   287  		return nil, err
   288  	}
   289  
   290  	return body, nil
   291  }
   292  
   293  // Create requests a node to be created
   294  func Create(ctx context.Context, client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
   295  	reqBody, err := opts.ToNodeCreateMap()
   296  	if err != nil {
   297  		r.Err = err
   298  		return
   299  	}
   300  
   301  	resp, err := client.Post(ctx, createURL(client), reqBody, &r.Body, nil)
   302  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   303  	return
   304  }
   305  
   306  type Patch interface {
   307  	ToNodeUpdateMap() (map[string]any, error)
   308  }
   309  
   310  // UpdateOpts is a slice of Patches used to update a node
   311  type UpdateOpts []Patch
   312  
   313  type UpdateOp string
   314  
   315  const (
   316  	ReplaceOp UpdateOp = "replace"
   317  	AddOp     UpdateOp = "add"
   318  	RemoveOp  UpdateOp = "remove"
   319  )
   320  
   321  type UpdateOperation struct {
   322  	Op    UpdateOp `json:"op" required:"true"`
   323  	Path  string   `json:"path" required:"true"`
   324  	Value any      `json:"value,omitempty"`
   325  }
   326  
   327  func (opts UpdateOperation) ToNodeUpdateMap() (map[string]any, error) {
   328  	return gophercloud.BuildRequestBody(opts, "")
   329  }
   330  
   331  // Update requests that a node be updated
   332  func Update(ctx context.Context, client *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
   333  	body := make([]map[string]any, len(opts))
   334  	for i, patch := range opts {
   335  		result, err := patch.ToNodeUpdateMap()
   336  		if err != nil {
   337  			r.Err = err
   338  			return
   339  		}
   340  
   341  		body[i] = result
   342  	}
   343  	resp, err := client.Patch(ctx, updateURL(client, id), body, &r.Body, &gophercloud.RequestOpts{
   344  		OkCodes: []int{200},
   345  	})
   346  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   347  	return
   348  }
   349  
   350  // Delete requests that a node be removed
   351  func Delete(ctx context.Context, client *gophercloud.ServiceClient, id string) (r DeleteResult) {
   352  	resp, err := client.Delete(ctx, deleteURL(client, id), nil)
   353  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   354  	return
   355  }
   356  
   357  // Request that Ironic validate whether the Node’s driver has enough information to manage the Node. This polls each
   358  // interface on the driver, and returns the status of that interface.
   359  func Validate(ctx context.Context, client *gophercloud.ServiceClient, id string) (r ValidateResult) {
   360  	resp, err := client.Get(ctx, validateURL(client, id), &r.Body, &gophercloud.RequestOpts{
   361  		OkCodes: []int{200},
   362  	})
   363  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   364  	return
   365  }
   366  
   367  // Inject NMI (Non-Masking Interrupts) for the given Node. This feature can be used for hardware diagnostics, and
   368  // actual support depends on a driver.
   369  func InjectNMI(ctx context.Context, client *gophercloud.ServiceClient, id string) (r InjectNMIResult) {
   370  	resp, err := client.Put(ctx, injectNMIURL(client, id), map[string]string{}, nil, &gophercloud.RequestOpts{
   371  		OkCodes: []int{204},
   372  	})
   373  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   374  	return
   375  }
   376  
   377  type BootDeviceOpts struct {
   378  	BootDevice string `json:"boot_device"` // e.g., 'pxe', 'disk', etc.
   379  	Persistent bool   `json:"persistent"`  // Whether this is one-time or not
   380  }
   381  
   382  // BootDeviceOptsBuilder allows extensions to add additional parameters to the
   383  // SetBootDevice request.
   384  type BootDeviceOptsBuilder interface {
   385  	ToBootDeviceMap() (map[string]any, error)
   386  }
   387  
   388  // ToBootDeviceSetMap assembles a request body based on the contents of a BootDeviceOpts.
   389  func (opts BootDeviceOpts) ToBootDeviceMap() (map[string]any, error) {
   390  	body, err := gophercloud.BuildRequestBody(opts, "")
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	return body, nil
   396  }
   397  
   398  // Set the boot device for the given Node, and set it persistently or for one-time boot. The exact behaviour
   399  // of this depends on the hardware driver.
   400  func SetBootDevice(ctx context.Context, client *gophercloud.ServiceClient, id string, bootDevice BootDeviceOptsBuilder) (r SetBootDeviceResult) {
   401  	reqBody, err := bootDevice.ToBootDeviceMap()
   402  	if err != nil {
   403  		r.Err = err
   404  		return
   405  	}
   406  
   407  	resp, err := client.Put(ctx, bootDeviceURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   408  		OkCodes: []int{204},
   409  	})
   410  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   411  	return
   412  }
   413  
   414  // Get the current boot device for the given Node.
   415  func GetBootDevice(ctx context.Context, client *gophercloud.ServiceClient, id string) (r BootDeviceResult) {
   416  	resp, err := client.Get(ctx, bootDeviceURL(client, id), &r.Body, &gophercloud.RequestOpts{
   417  		OkCodes: []int{200},
   418  	})
   419  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   420  	return
   421  }
   422  
   423  // Retrieve the acceptable set of supported boot devices for a specific Node.
   424  func GetSupportedBootDevices(ctx context.Context, client *gophercloud.ServiceClient, id string) (r SupportedBootDeviceResult) {
   425  	resp, err := client.Get(ctx, supportedBootDeviceURL(client, id), &r.Body, &gophercloud.RequestOpts{
   426  		OkCodes: []int{200},
   427  	})
   428  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   429  	return
   430  }
   431  
   432  // An interface type for a deploy (or clean) step.
   433  type StepInterface string
   434  
   435  const (
   436  	InterfaceBIOS       StepInterface = "bios"
   437  	InterfaceDeploy     StepInterface = "deploy"
   438  	InterfaceFirmware   StepInterface = "firmware"
   439  	InterfaceManagement StepInterface = "management"
   440  	InterfacePower      StepInterface = "power"
   441  	InterfaceRAID       StepInterface = "raid"
   442  )
   443  
   444  // A cleaning step has required keys ‘interface’ and ‘step’, and optional key ‘args’. If specified,
   445  // the value for ‘args’ is a keyword variable argument dictionary that is passed to the cleaning step
   446  // method.
   447  type CleanStep struct {
   448  	Interface StepInterface  `json:"interface" required:"true"`
   449  	Step      string         `json:"step" required:"true"`
   450  	Args      map[string]any `json:"args,omitempty"`
   451  }
   452  
   453  // A service step looks the same as a cleaning step.
   454  type ServiceStep = CleanStep
   455  
   456  // A deploy step has required keys ‘interface’, ‘step’, ’args’ and ’priority’.
   457  // The value for ‘args’ is a keyword variable argument dictionary that is passed to the deploy step
   458  // method. Priority is a numeric priority at which the step is running.
   459  type DeployStep struct {
   460  	Interface StepInterface  `json:"interface" required:"true"`
   461  	Step      string         `json:"step" required:"true"`
   462  	Args      map[string]any `json:"args" required:"true"`
   463  	Priority  int            `json:"priority" required:"true"`
   464  }
   465  
   466  // ProvisionStateOptsBuilder allows extensions to add additional parameters to the
   467  // ChangeProvisionState request.
   468  type ProvisionStateOptsBuilder interface {
   469  	ToProvisionStateMap() (map[string]any, error)
   470  }
   471  
   472  // Starting with Ironic API version 1.56, a configdrive may be a JSON object with structured data.
   473  // Prior to this version, it must be a base64-encoded, gzipped ISO9660 image.
   474  type ConfigDrive struct {
   475  	MetaData    map[string]any `json:"meta_data,omitempty"`
   476  	NetworkData map[string]any `json:"network_data,omitempty"`
   477  	UserData    any            `json:"user_data,omitempty"`
   478  }
   479  
   480  // ProvisionStateOpts for a request to change a node's provision state. A config drive should be base64-encoded
   481  // gzipped ISO9660 image. Deploy steps are supported starting with API 1.69.
   482  type ProvisionStateOpts struct {
   483  	Target         TargetProvisionState `json:"target" required:"true"`
   484  	ConfigDrive    any                  `json:"configdrive,omitempty"`
   485  	CleanSteps     []CleanStep          `json:"clean_steps,omitempty"`
   486  	DeploySteps    []DeployStep         `json:"deploy_steps,omitempty"`
   487  	ServiceSteps   []ServiceStep        `json:"service_steps,omitempty"`
   488  	RescuePassword string               `json:"rescue_password,omitempty"`
   489  }
   490  
   491  // ToProvisionStateMap assembles a request body based on the contents of a CreateOpts.
   492  func (opts ProvisionStateOpts) ToProvisionStateMap() (map[string]any, error) {
   493  	body, err := gophercloud.BuildRequestBody(opts, "")
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  
   498  	return body, nil
   499  }
   500  
   501  // Request a change to the Node’s provision state. Acceptable target states depend on the Node’s current provision
   502  // state. More detailed documentation of the Ironic State Machine is available in the developer docs.
   503  func ChangeProvisionState(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ProvisionStateOptsBuilder) (r ChangeStateResult) {
   504  	reqBody, err := opts.ToProvisionStateMap()
   505  	if err != nil {
   506  		r.Err = err
   507  		return
   508  	}
   509  
   510  	resp, err := client.Put(ctx, provisionStateURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   511  		OkCodes: []int{202},
   512  	})
   513  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   514  	return
   515  }
   516  
   517  type TargetPowerState string
   518  
   519  // TargetPowerState is used when changing the power state of a node.
   520  const (
   521  	PowerOn       TargetPowerState = "power on"
   522  	PowerOff      TargetPowerState = "power off"
   523  	Rebooting     TargetPowerState = "rebooting"
   524  	SoftPowerOff  TargetPowerState = "soft power off"
   525  	SoftRebooting TargetPowerState = "soft rebooting"
   526  )
   527  
   528  // PowerStateOptsBuilder allows extensions to add additional parameters to the ChangePowerState request.
   529  type PowerStateOptsBuilder interface {
   530  	ToPowerStateMap() (map[string]any, error)
   531  }
   532  
   533  // PowerStateOpts for a request to change a node's power state.
   534  type PowerStateOpts struct {
   535  	Target  TargetPowerState `json:"target" required:"true"`
   536  	Timeout int              `json:"timeout,omitempty"`
   537  }
   538  
   539  // ToPowerStateMap assembles a request body based on the contents of a PowerStateOpts.
   540  func (opts PowerStateOpts) ToPowerStateMap() (map[string]any, error) {
   541  	body, err := gophercloud.BuildRequestBody(opts, "")
   542  	if err != nil {
   543  		return nil, err
   544  	}
   545  
   546  	return body, nil
   547  }
   548  
   549  // Request to change a Node's power state.
   550  func ChangePowerState(ctx context.Context, client *gophercloud.ServiceClient, id string, opts PowerStateOptsBuilder) (r ChangePowerStateResult) {
   551  	reqBody, err := opts.ToPowerStateMap()
   552  	if err != nil {
   553  		r.Err = err
   554  		return
   555  	}
   556  
   557  	resp, err := client.Put(ctx, powerStateURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   558  		OkCodes: []int{202},
   559  	})
   560  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   561  	return
   562  }
   563  
   564  // This is the desired RAID configuration on the bare metal node.
   565  type RAIDConfigOpts struct {
   566  	LogicalDisks []LogicalDisk `json:"logical_disks"`
   567  }
   568  
   569  // RAIDConfigOptsBuilder allows extensions to modify a set RAID config request.
   570  type RAIDConfigOptsBuilder interface {
   571  	ToRAIDConfigMap() (map[string]any, error)
   572  }
   573  
   574  // RAIDLevel type is used to specify the RAID level for a logical disk.
   575  type RAIDLevel string
   576  
   577  const (
   578  	RAID0  RAIDLevel = "0"
   579  	RAID1  RAIDLevel = "1"
   580  	RAID2  RAIDLevel = "2"
   581  	RAID5  RAIDLevel = "5"
   582  	RAID6  RAIDLevel = "6"
   583  	RAID10 RAIDLevel = "1+0"
   584  	RAID50 RAIDLevel = "5+0"
   585  	RAID60 RAIDLevel = "6+0"
   586  	JBOD   RAIDLevel = "JBOD"
   587  )
   588  
   589  // DiskType is used to specify the disk type for a logical disk, e.g. hdd or ssd.
   590  type DiskType string
   591  
   592  const (
   593  	HDD DiskType = "hdd"
   594  	SSD DiskType = "ssd"
   595  )
   596  
   597  // InterfaceType is used to specify the interface for a logical disk.
   598  type InterfaceType string
   599  
   600  const (
   601  	SATA InterfaceType = "sata"
   602  	SCSI InterfaceType = "scsi"
   603  	SAS  InterfaceType = "sas"
   604  )
   605  
   606  type LogicalDisk struct {
   607  	// Size (Integer) of the logical disk to be created in GiB.  If unspecified, "MAX" will be used.
   608  	SizeGB *int `json:"size_gb"`
   609  
   610  	// RAID level for the logical disk.
   611  	RAIDLevel RAIDLevel `json:"raid_level" required:"true"`
   612  
   613  	// Name of the volume. Should be unique within the Node. If not specified, volume name will be auto-generated.
   614  	VolumeName string `json:"volume_name,omitempty"`
   615  
   616  	// Set to true if this is the root volume. At most one logical disk can have this set to true.
   617  	IsRootVolume *bool `json:"is_root_volume,omitempty"`
   618  
   619  	// Set to true if this logical disk can share physical disks with other logical disks.
   620  	SharePhysicalDisks *bool `json:"share_physical_disks,omitempty"`
   621  
   622  	// If this is not specified, disk type will not be a criterion to find backing physical disks
   623  	DiskType DiskType `json:"disk_type,omitempty"`
   624  
   625  	// If this is not specified, interface type will not be a criterion to find backing physical disks.
   626  	InterfaceType InterfaceType `json:"interface_type,omitempty"`
   627  
   628  	// Integer, number of disks to use for the logical disk. Defaults to minimum number of disks required
   629  	// for the particular RAID level.
   630  	NumberOfPhysicalDisks int `json:"number_of_physical_disks,omitempty"`
   631  
   632  	// The name of the controller as read by the RAID interface.
   633  	Controller string `json:"controller,omitempty"`
   634  
   635  	// A list of physical disks to use as read by the RAID interface.
   636  	PhysicalDisks []any `json:"physical_disks,omitempty"`
   637  }
   638  
   639  func (opts RAIDConfigOpts) ToRAIDConfigMap() (map[string]any, error) {
   640  	body, err := gophercloud.BuildRequestBody(opts, "")
   641  	if err != nil {
   642  		return nil, err
   643  	}
   644  
   645  	if body["logical_disks"] != nil {
   646  		for _, v := range body["logical_disks"].([]any) {
   647  			if logicalDisk, ok := v.(map[string]any); ok {
   648  				if logicalDisk["size_gb"] == nil {
   649  					logicalDisk["size_gb"] = "MAX"
   650  				}
   651  			}
   652  		}
   653  	}
   654  
   655  	return body, nil
   656  }
   657  
   658  // Request to change a Node's RAID config.
   659  func SetRAIDConfig(ctx context.Context, client *gophercloud.ServiceClient, id string, raidConfigOptsBuilder RAIDConfigOptsBuilder) (r ChangeStateResult) {
   660  	reqBody, err := raidConfigOptsBuilder.ToRAIDConfigMap()
   661  	if err != nil {
   662  		r.Err = err
   663  		return
   664  	}
   665  
   666  	resp, err := client.Put(ctx, raidConfigURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   667  		OkCodes: []int{204},
   668  	})
   669  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   670  	return
   671  }
   672  
   673  // ListBIOSSettingsOptsBuilder allows extensions to add additional parameters to the
   674  // ListBIOSSettings request.
   675  type ListBIOSSettingsOptsBuilder interface {
   676  	ToListBIOSSettingsOptsQuery() (string, error)
   677  }
   678  
   679  // ListBIOSSettingsOpts defines query options that can be passed to ListBIOSettings
   680  type ListBIOSSettingsOpts struct {
   681  	// Provide additional information for the BIOS Settings
   682  	Detail bool `q:"detail"`
   683  
   684  	// One or more fields to be returned in the response.
   685  	Fields []string `q:"fields" format:"comma-separated"`
   686  }
   687  
   688  // ToListBIOSSettingsOptsQuery formats a ListBIOSSettingsOpts into a query string
   689  func (opts ListBIOSSettingsOpts) ToListBIOSSettingsOptsQuery() (string, error) {
   690  	if opts.Detail && len(opts.Fields) > 0 {
   691  		return "", fmt.Errorf("cannot have both fields and detail options for BIOS settings")
   692  	}
   693  
   694  	q, err := gophercloud.BuildQueryString(opts)
   695  	return q.String(), err
   696  }
   697  
   698  // Get the current BIOS Settings for the given Node.
   699  // To use the opts requires microversion 1.74.
   700  func ListBIOSSettings(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ListBIOSSettingsOptsBuilder) (r ListBIOSSettingsResult) {
   701  	url := biosListSettingsURL(client, id)
   702  	if opts != nil {
   703  
   704  		query, err := opts.ToListBIOSSettingsOptsQuery()
   705  		if err != nil {
   706  			r.Err = err
   707  			return
   708  		}
   709  		url += query
   710  	}
   711  
   712  	resp, err := client.Get(ctx, url, &r.Body, &gophercloud.RequestOpts{
   713  		OkCodes: []int{200},
   714  	})
   715  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   716  	return
   717  }
   718  
   719  // Get one BIOS Setting for the given Node.
   720  func GetBIOSSetting(ctx context.Context, client *gophercloud.ServiceClient, id string, setting string) (r GetBIOSSettingResult) {
   721  	resp, err := client.Get(ctx, biosGetSettingURL(client, id, setting), &r.Body, &gophercloud.RequestOpts{
   722  		OkCodes: []int{200},
   723  	})
   724  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   725  	return
   726  }
   727  
   728  // CallVendorPassthruOpts defines query options that can be passed to any VendorPassthruCall
   729  type CallVendorPassthruOpts struct {
   730  	Method string `q:"method"`
   731  }
   732  
   733  // ToGetSubscriptionMap assembles a query based on the contents of a CallVendorPassthruOpts
   734  func ToGetAllSubscriptionMap(opts CallVendorPassthruOpts) (string, error) {
   735  	q, err := gophercloud.BuildQueryString(opts)
   736  	return q.String(), err
   737  }
   738  
   739  // Get all vendor_passthru methods available for the given Node.
   740  func GetVendorPassthruMethods(ctx context.Context, client *gophercloud.ServiceClient, id string) (r VendorPassthruMethodsResult) {
   741  	resp, err := client.Get(ctx, vendorPassthruMethodsURL(client, id), &r.Body, &gophercloud.RequestOpts{
   742  		OkCodes: []int{200},
   743  	})
   744  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   745  	return
   746  }
   747  
   748  // Get all subscriptions available for the given Node.
   749  func GetAllSubscriptions(ctx context.Context, client *gophercloud.ServiceClient, id string, method CallVendorPassthruOpts) (r GetAllSubscriptionsVendorPassthruResult) {
   750  	query, err := ToGetAllSubscriptionMap(method)
   751  	if err != nil {
   752  		r.Err = err
   753  		return
   754  	}
   755  	url := vendorPassthruCallURL(client, id) + query
   756  	resp, err := client.Get(ctx, url, &r.Body, &gophercloud.RequestOpts{
   757  		OkCodes: []int{200},
   758  	})
   759  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   760  	return
   761  }
   762  
   763  // The desired subscription id on the baremetal node.
   764  type GetSubscriptionOpts struct {
   765  	Id string `json:"id"`
   766  }
   767  
   768  // ToGetSubscriptionMap assembles a query based on the contents of CallVendorPassthruOpts and a request body based on the contents of a GetSubscriptionOpts
   769  func ToGetSubscriptionMap(method CallVendorPassthruOpts, opts GetSubscriptionOpts) (string, map[string]any, error) {
   770  	q, err := gophercloud.BuildQueryString(method)
   771  	if err != nil {
   772  		return q.String(), nil, err
   773  	}
   774  	body, err := gophercloud.BuildRequestBody(opts, "")
   775  	if err != nil {
   776  		return q.String(), nil, err
   777  	}
   778  
   779  	return q.String(), body, nil
   780  }
   781  
   782  // Get a subscription on the given Node.
   783  func GetSubscription(ctx context.Context, client *gophercloud.ServiceClient, id string, method CallVendorPassthruOpts, subscriptionOpts GetSubscriptionOpts) (r SubscriptionVendorPassthruResult) {
   784  	query, reqBody, err := ToGetSubscriptionMap(method, subscriptionOpts)
   785  	if err != nil {
   786  		r.Err = err
   787  		return
   788  	}
   789  	url := vendorPassthruCallURL(client, id) + query
   790  	resp, err := client.Get(ctx, url, &r.Body, &gophercloud.RequestOpts{
   791  		JSONBody: reqBody,
   792  		OkCodes:  []int{200},
   793  	})
   794  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   795  	return
   796  }
   797  
   798  // The desired subscription to be deleted from the baremetal node.
   799  type DeleteSubscriptionOpts struct {
   800  	Id string `json:"id"`
   801  }
   802  
   803  // ToDeleteSubscriptionMap assembles a query based on the contents of CallVendorPassthruOpts and a request body based on the contents of a DeleteSubscriptionOpts
   804  func ToDeleteSubscriptionMap(method CallVendorPassthruOpts, opts DeleteSubscriptionOpts) (string, map[string]any, error) {
   805  	q, err := gophercloud.BuildQueryString(method)
   806  	if err != nil {
   807  		return q.String(), nil, err
   808  	}
   809  	body, err := gophercloud.BuildRequestBody(opts, "")
   810  	if err != nil {
   811  		return q.String(), nil, err
   812  	}
   813  	return q.String(), body, nil
   814  }
   815  
   816  // Delete a subscription on the given node.
   817  func DeleteSubscription(ctx context.Context, client *gophercloud.ServiceClient, id string, method CallVendorPassthruOpts, subscriptionOpts DeleteSubscriptionOpts) (r DeleteSubscriptionVendorPassthruResult) {
   818  	query, reqBody, err := ToDeleteSubscriptionMap(method, subscriptionOpts)
   819  	if err != nil {
   820  		r.Err = err
   821  		return
   822  	}
   823  	url := vendorPassthruCallURL(client, id) + query
   824  	resp, err := client.Delete(ctx, url, &gophercloud.RequestOpts{
   825  		JSONBody: reqBody,
   826  		OkCodes:  []int{200, 202, 204},
   827  	})
   828  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   829  	return r
   830  }
   831  
   832  // The desired subscription to be created from the baremetal node.
   833  type CreateSubscriptionOpts struct {
   834  	Destination string              `json:"Destination"`
   835  	EventTypes  []string            `json:"EventTypes,omitempty"`
   836  	HttpHeaders []map[string]string `json:"HttpHeaders,omitempty"`
   837  	Context     string              `json:"Context,omitempty"`
   838  	Protocol    string              `json:"Protocol,omitempty"`
   839  }
   840  
   841  // ToCreateSubscriptionMap assembles a query based on the contents of CallVendorPassthruOpts and a request body based on the contents of a CreateSubscriptionOpts
   842  func ToCreateSubscriptionMap(method CallVendorPassthruOpts, opts CreateSubscriptionOpts) (string, map[string]any, error) {
   843  	q, err := gophercloud.BuildQueryString(method)
   844  	if err != nil {
   845  		return q.String(), nil, err
   846  	}
   847  	body, err := gophercloud.BuildRequestBody(opts, "")
   848  	if err != nil {
   849  		return q.String(), nil, err
   850  	}
   851  	return q.String(), body, nil
   852  }
   853  
   854  // Creates a subscription on the given node.
   855  func CreateSubscription(ctx context.Context, client *gophercloud.ServiceClient, id string, method CallVendorPassthruOpts, subscriptionOpts CreateSubscriptionOpts) (r SubscriptionVendorPassthruResult) {
   856  	query, reqBody, err := ToCreateSubscriptionMap(method, subscriptionOpts)
   857  	if err != nil {
   858  		r.Err = err
   859  		return
   860  	}
   861  	url := vendorPassthruCallURL(client, id) + query
   862  	resp, err := client.Post(ctx, url, reqBody, &r.Body, &gophercloud.RequestOpts{
   863  		OkCodes: []int{200},
   864  	})
   865  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   866  	return r
   867  }
   868  
   869  // MaintenanceOpts for a request to set the node's maintenance mode.
   870  type MaintenanceOpts struct {
   871  	Reason string `json:"reason,omitempty"`
   872  }
   873  
   874  // MaintenanceOptsBuilder allows extensions to add additional parameters to the SetMaintenance request.
   875  type MaintenanceOptsBuilder interface {
   876  	ToMaintenanceMap() (map[string]any, error)
   877  }
   878  
   879  // ToMaintenanceMap assembles a request body based on the contents of a MaintenanceOpts.
   880  func (opts MaintenanceOpts) ToMaintenanceMap() (map[string]any, error) {
   881  	body, err := gophercloud.BuildRequestBody(opts, "")
   882  	if err != nil {
   883  		return nil, err
   884  	}
   885  
   886  	return body, nil
   887  }
   888  
   889  // Request to set the Node's maintenance mode.
   890  func SetMaintenance(ctx context.Context, client *gophercloud.ServiceClient, id string, opts MaintenanceOptsBuilder) (r SetMaintenanceResult) {
   891  	reqBody, err := opts.ToMaintenanceMap()
   892  	if err != nil {
   893  		r.Err = err
   894  		return
   895  	}
   896  
   897  	resp, err := client.Put(ctx, maintenanceURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   898  		OkCodes: []int{202},
   899  	})
   900  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   901  	return
   902  }
   903  
   904  // Request to unset the Node's maintenance mode.
   905  func UnsetMaintenance(ctx context.Context, client *gophercloud.ServiceClient, id string) (r SetMaintenanceResult) {
   906  	resp, err := client.Delete(ctx, maintenanceURL(client, id), &gophercloud.RequestOpts{
   907  		OkCodes: []int{202},
   908  	})
   909  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   910  	return
   911  }
   912  
   913  // GetInventory return stored data from successful inspection.
   914  func GetInventory(ctx context.Context, client *gophercloud.ServiceClient, id string) (r InventoryResult) {
   915  	resp, err := client.Get(ctx, inventoryURL(client, id), &r.Body, &gophercloud.RequestOpts{
   916  		OkCodes: []int{200},
   917  	})
   918  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   919  	return
   920  }
   921  
   922  // ListFirmware return the list of Firmware components for the given Node.
   923  func ListFirmware(ctx context.Context, client *gophercloud.ServiceClient, id string) (r ListFirmwareResult) {
   924  	resp, err := client.Get(ctx, firmwareListURL(client, id), &r.Body, &gophercloud.RequestOpts{
   925  		OkCodes: []int{200},
   926  	})
   927  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   928  	return
   929  }
   930  
   931  type VirtualMediaDeviceType string
   932  
   933  const (
   934  	VirtualMediaDisk   VirtualMediaDeviceType = "disk"
   935  	VirtualMediaCD     VirtualMediaDeviceType = "cdrom"
   936  	VirtualMediaFloppy VirtualMediaDeviceType = "floppy"
   937  )
   938  
   939  type ImageDownloadSource string
   940  
   941  const (
   942  	ImageDownloadSourceHTTP  ImageDownloadSource = "http"
   943  	ImageDownloadSourceLocal ImageDownloadSource = "local"
   944  	ImageDownloadSourceSwift ImageDownloadSource = "swift"
   945  )
   946  
   947  // The desired virtual media attachment on the baremetal node.
   948  type AttachVirtualMediaOpts struct {
   949  	DeviceType          VirtualMediaDeviceType `json:"device_type"`
   950  	ImageURL            string                 `json:"image_url"`
   951  	ImageDownloadSource ImageDownloadSource    `json:"image_download_source,omitempty"`
   952  }
   953  
   954  type AttachVirtualMediaOptsBuilder interface {
   955  	ToAttachVirtualMediaMap() (map[string]any, error)
   956  }
   957  
   958  func (opts AttachVirtualMediaOpts) ToAttachVirtualMediaMap() (map[string]any, error) {
   959  	return gophercloud.BuildRequestBody(opts, "")
   960  }
   961  
   962  // Request to attach a virtual media device to the Node.
   963  func AttachVirtualMedia(ctx context.Context, client *gophercloud.ServiceClient, id string, opts AttachVirtualMediaOptsBuilder) (r VirtualMediaAttachResult) {
   964  	reqBody, err := opts.ToAttachVirtualMediaMap()
   965  	if err != nil {
   966  		r.Err = err
   967  		return
   968  	}
   969  
   970  	resp, err := client.Post(ctx, virtualMediaURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
   971  		OkCodes: []int{204},
   972  	})
   973  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
   974  	return
   975  }
   976  
   977  // The desired virtual media detachment on the baremetal node.
   978  type DetachVirtualMediaOpts struct {
   979  	DeviceTypes []VirtualMediaDeviceType `q:"device_types" format:"comma-separated"`
   980  }
   981  
   982  type DetachVirtualMediaOptsBuilder interface {
   983  	ToDetachVirtualMediaOptsQuery() (string, error)
   984  }
   985  
   986  func (opts DetachVirtualMediaOpts) ToDetachVirtualMediaOptsQuery() (string, error) {
   987  	q, err := gophercloud.BuildQueryString(opts)
   988  	return q.String(), err
   989  }
   990  
   991  // Request to detach a virtual media device from the Node.
   992  func DetachVirtualMedia(ctx context.Context, client *gophercloud.ServiceClient, id string, opts DetachVirtualMediaOptsBuilder) (r VirtualMediaDetachResult) {
   993  	query, err := opts.ToDetachVirtualMediaOptsQuery()
   994  	if err != nil {
   995  		r.Err = err
   996  		return
   997  	}
   998  
   999  	resp, err := client.Delete(ctx, virtualMediaURL(client, id)+query, &gophercloud.RequestOpts{
  1000  		OkCodes: []int{204},
  1001  	})
  1002  	_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
  1003  	return
  1004  }