diff --git a/.golangci.yaml b/.golangci.yaml index ab02c2a9..4722d982 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -38,7 +38,6 @@ run: # If it's not please let us know. # "/" will be replaced by current OS file path separator to properly work on Windows. skip-files: - - "redfish/provider/data_source_redfish_system_boot.go" - "redfish/provider/resource_redfish_storage_volume.go" - "redfish/provider/resource_redfish_storage_volume.go" # - ".*\\.my\\.go$" diff --git a/docs/data-sources/system_boot.md b/docs/data-sources/system_boot.md new file mode 100644 index 00000000..b870f20b --- /dev/null +++ b/docs/data-sources/system_boot.md @@ -0,0 +1,81 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "redfish_system_boot Data Source - terraform-provider-redfish" +subcategory: "" +description: |- + Data source to fetch Firmware Inventory details via RedFish. +--- + +# redfish_system_boot (Data Source) + +Data source to fetch Firmware Inventory details via RedFish. + +## Example Usage + +```terraform +/* +Copyright (c) 2023 Dell Inc., or its subsidiaries. All Rights Reserved. + +Licensed under the Mozilla Public License Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://mozilla.org/MPL/2.0/ + + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +data "redfish_system_boot" "system_boot" { + for_each = var.rack1 + + redfish_server { + user = each.value.user + password = each.value.password + endpoint = each.value.endpoint + ssl_insecure = each.value.ssl_insecure + } + + // resource_id is an optional argument. By default, the data source uses + // the first ComputerSystem resource present in the ComputerSystem collection + resource_id = "System.Embedded.1" +} + +output "system_boot" { + value = data.redfish_system_boot.system_boot + sensitive = true +} +``` + + +## Schema + +### Optional + +- `id` (String) Resource ID of the computer system. If not provided, the first system resource is used +- `redfish_server` (Block List) List of server BMCs and their respective user credentials (see [below for nested schema](#nestedblock--redfish_server)) + +### Read-Only + +- `boot_order` (List of String) An array of BootOptionReference strings that represent the persistent boot order for this computer system +- `boot_source_override_enabled` (String) The state of the boot source override feature +- `boot_source_override_mode` (String) The BIOS boot mode to use when the system boots from the BootSourceOverrideTarget boot source +- `boot_source_override_target` (String) Current boot source to use at next boot instead of the normal boot device, if BootSourceOverrideEnabled is true +- `uefi_target_boot_source_override` (String) The UEFI device path of the device from which to boot when BootSourceOverrideTarget is UefiTarget + + +### Nested Schema for `redfish_server` + +Required: + +- `endpoint` (String) Server BMC IP address or hostname + +Optional: + +- `password` (String, Sensitive) User password for login +- `ssl_insecure` (Boolean) This field indicates whether the SSL/TLS certificate must be verified or not +- `user` (String) User name for login diff --git a/redfish/models/system_boot.go b/redfish/models/system_boot.go new file mode 100644 index 00000000..e5466a26 --- /dev/null +++ b/redfish/models/system_boot.go @@ -0,0 +1,16 @@ +package models + +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// SystemBootDataSource struct for datasource +type SystemBootDataSource struct { + RedfishServer []RedfishServer `tfsdk:"redfish_server"` + ResourceID types.String `tfsdk:"id"` + BootOrder types.List `tfsdk:"boot_order"` + BootSourceOverrideEnabled types.String `tfsdk:"boot_source_override_enabled"` + BootSourceOverrideMode types.String `tfsdk:"boot_source_override_mode"` + BootSourceOverrideTarget types.String `tfsdk:"boot_source_override_target"` + UefiTargetBootSourceOverride types.String `tfsdk:"uefi_target_boot_source_override"` +} diff --git a/redfish/provider/data_source_redfish_system_boot.go b/redfish/provider/data_source_redfish_system_boot.go index 53b16a30..b3edbb5a 100644 --- a/redfish/provider/data_source_redfish_system_boot.go +++ b/redfish/provider/data_source_redfish_system_boot.go @@ -1,149 +1,156 @@ package provider -// import ( -// "context" - -// "github.com/hashicorp/terraform-plugin-sdk/v2/diag" -// "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -// "github.com/stmcginnis/gofish" -// "github.com/stmcginnis/gofish/redfish" -// ) - -// func dataSourceRedfishSystemBoot() *schema.Resource { -// return &schema.Resource{ -// ReadContext: dataSourceRedfishSystemBootRead, -// Schema: getDataSourceRedfishSystemBootSchema(), -// } -// } - -// func getDataSourceRedfishSystemBootSchema() map[string]*schema.Schema { -// return map[string]*schema.Schema{ -// "redfish_server": { -// Type: schema.TypeList, -// Required: true, -// Description: "List of server BMCs and their respective user credentials", -// Elem: &schema.Resource{ -// Schema: map[string]*schema.Schema{ -// "user": { -// Type: schema.TypeString, -// Optional: true, -// Description: "User name for login", -// }, -// "password": { -// Type: schema.TypeString, -// Optional: true, -// Description: "User password for login", -// Sensitive: true, -// }, -// "endpoint": { -// Type: schema.TypeString, -// Required: true, -// Description: "Server BMC IP address or hostname", -// }, -// "ssl_insecure": { -// Type: schema.TypeBool, -// Optional: true, -// Description: "This field indicates whether the SSL/TLS certificate must be verified or not", -// }, -// }, -// }, -// }, -// "resource_id": { -// Type: schema.TypeString, -// Optional: true, -// Description: "Resource ID of the computer system resource. If not provided, then the first system resource is used from the computer system collection", -// }, -// "boot_order": { -// Type: schema.TypeList, -// Computed: true, -// Description: "An array of BootOptionReference strings that represent the persistent boot order for this computer system", -// Elem: &schema.Schema{ -// Type: schema.TypeString, -// }, -// }, -// "boot_source_override_enabled": { -// Type: schema.TypeString, -// Computed: true, -// Description: "The state of the boot source override feature", -// }, -// "boot_source_override_mode": { -// Type: schema.TypeString, -// Computed: true, -// Description: "The BIOS boot mode to use when the system boots from the BootSourceOverrideTarget boot source", -// }, -// "boot_source_override_target": { -// Type: schema.TypeString, -// Computed: true, -// Description: "The current boot source to use at the next boot instead of the normal boot device, if BootSourceOverrideEnabled is true", -// }, -// "uefi_target_boot_source_override": { -// Type: schema.TypeString, -// Computed: true, -// Description: "The UEFI device path of the device from which to boot when BootSourceOverrideTarget is UefiTarget", -// }, -// } -// } - -// func dataSourceRedfishSystemBootRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { -// service, err := NewConfig(m.(*schema.ResourceData), d) -// if err != nil { -// return diag.Errorf(err.Error()) -// } - -// return readRedfishSystemBoot(service, d) -// } - -// func readRedfishSystemBoot(service *gofish.Service, d *schema.ResourceData) diag.Diagnostics { -// var diags diag.Diagnostics - -// systems, err := service.Systems() -// if err != nil { -// return diag.Errorf("Error when retrieving systems: %s", err) -// } - -// // get the boot resource -// var computerSystem *redfish.ComputerSystem -// var boot redfish.Boot -// if systemResourceId, ok := d.GetOk("resource_id"); ok { -// for key := range systems { -// if systems[key].ID == systemResourceId { -// computerSystem = systems[key] -// boot = systems[key].Boot -// break -// } -// } - -// if computerSystem == nil { -// return diag.Errorf("Could not find a ComputerSystem resource with resource ID = %s", systemResourceId) -// } -// } else { -// // use the first system resource in the collection if resource -// // ID is not provided -// computerSystem = systems[0] -// boot = systems[0].Boot -// } - -// if err := d.Set("boot_order", boot.BootOrder); err != nil { -// return diag.Errorf("error setting BootOrder: %s", err) -// } - -// if err := d.Set("boot_source_override_enabled", boot.BootSourceOverrideEnabled); err != nil { -// return diag.Errorf("error setting BootSourceOverrideEnabled: %s", err) -// } - -// if err := d.Set("boot_source_override_mode", boot.BootSourceOverrideMode); err != nil { -// return diag.Errorf("error setting BootSourceOverrideMode: %s", err) -// } - -// if err := d.Set("boot_source_override_target", boot.BootSourceOverrideTarget); err != nil { -// return diag.Errorf("error setting BootSourceOverrideTarget: %s", err) -// } - -// if err := d.Set("uefi_target_boot_source_override", boot.UefiTargetBootSourceOverride); err != nil { -// return diag.Errorf("error setting UefiTargetBootSourceOverride: %s", err) -// } - -// // set computer system ODataID as the resource ID -// d.SetId(computerSystem.ODataID) -// return diags -// } +import ( + "context" + "terraform-provider-redfish/redfish/models" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/stmcginnis/gofish" + "github.com/stmcginnis/gofish/redfish" +) + +var ( + _ datasource.DataSource = &SystemBootDatasource{} + _ datasource.DataSourceWithConfigure = &SystemBootDatasource{} +) + +// NewSystemBootDatasource is new datasource for group devices +func NewSystemBootDatasource() datasource.DataSource { + return &SystemBootDatasource{} +} + +// SystemBootDatasource to construct datasource +type SystemBootDatasource struct { + p *redfishProvider +} + +// Configure implements datasource.DataSourceWithConfigure +func (g *SystemBootDatasource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + g.p = req.ProviderData.(*redfishProvider) +} + +// Metadata implements datasource.DataSource +func (*SystemBootDatasource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "system_boot" +} + +// Schema implements datasource.DataSource +func (*SystemBootDatasource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Data source to fetch Firmware Inventory details via RedFish.", + Attributes: SystemBootDatasourceSchema(), + Blocks: RedfishServerDatasourceBlockMap(), + } +} + +// SystemBootDatasourceSchema to define the system boot datasource schema +func SystemBootDatasourceSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "Resource ID of the computer system. If not provided, the first system resource is used", + Description: "Resource ID of the computer system. If not provided, the first system resource is used", + Optional: true, + }, + "boot_order": schema.ListAttribute{ + MarkdownDescription: "An array of BootOptionReference strings that represent the persistent boot order for this computer system", + Description: "An array of BootOptionReference strings that represent the persistent boot order for this computer system", + Computed: true, + ElementType: types.StringType, + }, + "boot_source_override_enabled": schema.StringAttribute{ + MarkdownDescription: "The state of the boot source override feature", + Description: "The state of the boot source override feature", + Computed: true, + }, + "boot_source_override_mode": schema.StringAttribute{ + MarkdownDescription: "The BIOS boot mode to use when the system boots from the BootSourceOverrideTarget boot source", + Description: "The BIOS boot mode to use when the system boots from the BootSourceOverrideTarget boot source", + Computed: true, + }, + "boot_source_override_target": schema.StringAttribute{ + MarkdownDescription: "Current boot source to use at next boot instead of the normal boot device, if BootSourceOverrideEnabled is true", + Description: "Current boot source to use at next boot instead of the normal boot device, if BootSourceOverrideEnabled is true", + Computed: true, + }, + "uefi_target_boot_source_override": schema.StringAttribute{ + MarkdownDescription: "The UEFI device path of the device from which to boot when BootSourceOverrideTarget is UefiTarget", + Description: "The UEFI device path of the device from which to boot when BootSourceOverrideTarget is UefiTarget", + Computed: true, + }, + } +} + +// Read implements datasource.DataSource +func (g *SystemBootDatasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var plan models.SystemBootDataSource + diags := req.Config.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + service, err := NewConfig(g.p, &plan.RedfishServer) + if err != nil { + resp.Diagnostics.AddError("service error", err.Error()) + return + } + state, diags := readRedfishSystemBoot(service, &plan) + if err != nil { + diags.AddError("failed to fetch firmware inventory details", err.Error()) + } + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func readRedfishSystemBoot(service *gofish.Service, d *models.SystemBootDataSource) (*models.SystemBootDataSource, diag.Diagnostics) { + var diags diag.Diagnostics + + systems, err := service.Systems() + if err != nil { + diags.AddError("Error when retrieving systems", err.Error()) + return nil, diags + } + + // get the boot resource + var computerSystem *redfish.ComputerSystem + var boot redfish.Boot + if d.ResourceID.ValueString() != "" { + for key := range systems { + if systems[key].ID == d.ResourceID.ValueString() { + computerSystem = systems[key] + boot = systems[key].Boot + break + } + } + + if computerSystem == nil { + diags.AddError("Could not find a ComputerSystem", "") + return nil, diags + } + } else { + // use the first system resource in the collection if resource + // ID is not provided + computerSystem = systems[0] + boot = systems[0].Boot + } + + bootOrder := []attr.Value{} + for _, bootOptionReference := range boot.BootOrder { + bootOrder = append(bootOrder, types.StringValue(string(bootOptionReference))) + } + + d.BootOrder, diags = types.ListValue(types.StringType, bootOrder) + d.BootSourceOverrideEnabled = types.StringValue(string(boot.BootSourceOverrideEnabled)) + d.BootSourceOverrideMode = types.StringValue(string(boot.BootSourceOverrideMode)) + d.BootSourceOverrideTarget = types.StringValue(string(boot.BootSourceOverrideTarget)) + d.UefiTargetBootSourceOverride = types.StringValue(string(boot.UefiTargetBootSourceOverride)) + d.ResourceID = types.StringValue(computerSystem.ODataID) + + return d, diags +} diff --git a/redfish/provider/data_source_redfish_system_boot_test.go b/redfish/provider/data_source_redfish_system_boot_test.go index 387aa5c0..b262450b 100644 --- a/redfish/provider/data_source_redfish_system_boot_test.go +++ b/redfish/provider/data_source_redfish_system_boot_test.go @@ -30,7 +30,7 @@ func TestAccRedfishSystemBoot_fetchInvalidID(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRedfishDatasourceSystemBootConfig(creds, "invalid-id"), - ExpectError: regexp.MustCompile(" Could not find a ComputerSystem resource with resource ID"), + ExpectError: regexp.MustCompile("Could not find a ComputerSystem"), }, }, }) @@ -39,7 +39,7 @@ func TestAccRedfishSystemBoot_fetchInvalidID(t *testing.T) { func testAccRedfishDatasourceSystemBootConfig(testingInfo TestingServerCredentials, id string) string { return fmt.Sprintf(` data "redfish_system_boot" "system_boot" { - resource_id = "%s" + id = "%s" redfish_server { user = "%s" password = "%s" diff --git a/redfish/provider/provider.go b/redfish/provider/provider.go index eee5d044..53a36c3c 100644 --- a/redfish/provider/provider.go +++ b/redfish/provider/provider.go @@ -113,6 +113,7 @@ func (*redfishProvider) DataSources(_ context.Context) []func() datasource.DataS NewDellIdracAttributesDatasource, NewStorageDatasource, NewDellVirtualMediaDatasource, + NewSystemBootDatasource, NewFirmwareInventoryDatasource, } }