Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Storage linked collections #333

Merged
merged 1 commit into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 23 additions & 126 deletions redfish/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ type Storage struct {
AutoVolumeCreate AutoVolumeCreate
// Connections shall contain a link to a resource collection of type ConnectionCollection. The members of this
// collection shall reference Connection resources subordinate to Fabric resources.
connections []string
connections string
// ConsistencyGroups shall contain a link to a resource collection of type ConsistencyGroupCollection. The property
// shall be used when groups of volumes are treated as a single resource by an application or set of applications.
consistencyGroups []string
consistencyGroups string
// Controllers shall contain a link to a resource collection of type StorageControllerCollection that contains the
// set of storage controllers allocated to this storage subsystem.
controllers []string
controllers string
// Description provides a description of this resource.
Description string
// Drives is a collection that indicates all the drives attached to the
Expand All @@ -117,10 +117,10 @@ type Storage struct {
EncryptionMode EncryptionMode
// EndpointGroups shall contain a link to a resource collection of type EndpointGroupCollection. This property
// shall be implemented when atomic control is needed to perform mapping, masking, and zoning operations.
endpointGroups []string
endpointGroups string
// FileSystems shall contain a link to a resource collection of type FileSystemCollection. This property shall be
// used when file systems are shared or exported by the storage subsystem.
fileSystems []string
fileSystems string
// HotspareActivationPolicy shall contain the policy under which all drives operating as hot spares in this storage
// domain will activate.
HotspareActivationPolicy HotspareActivationPolicy
Expand All @@ -147,7 +147,7 @@ type Storage struct {
// StoragePools shall contain a link to a resource collection of type StoragePoolCollection. This property shall be
// used when an abstraction of media, rather than references to individual media, are used as the storage data
// source.
storagePools []string
storagePools string
// Volumes is a collection that indicates all the volumes produced by the
// storage controllers that this resource represents.
volumes string
Expand Down Expand Up @@ -205,13 +205,13 @@ func (storage *Storage) UnmarshalJSON(b []byte) error {
var t struct {
temp
Links links
Connections common.Links
ConsistencyGroups common.Links
Controllers common.Links
Connections common.Link
ConsistencyGroups common.Link
Controllers common.Link
Drives common.Links
EndpointGroups common.Links
FileSystems common.Links
StoragePools common.Links
EndpointGroups common.Link
FileSystems common.Link
StoragePools common.Link
Volumes common.Link
Actions actions
}
Expand All @@ -224,13 +224,13 @@ func (storage *Storage) UnmarshalJSON(b []byte) error {
*storage = Storage(t.temp)

// Extract the links to other entities for later
storage.connections = t.Connections.ToStrings()
storage.consistencyGroups = t.ConsistencyGroups.ToStrings()
storage.controllers = t.Controllers.ToStrings()
storage.connections = t.Connections.String()
storage.consistencyGroups = t.ConsistencyGroups.String()
storage.controllers = t.Controllers.String()
storage.drives = t.Drives.ToStrings()
storage.endpointGroups = t.EndpointGroups.ToStrings()
storage.fileSystems = t.FileSystems.ToStrings()
storage.storagePools = t.StoragePools.ToStrings()
storage.endpointGroups = t.EndpointGroups.String()
storage.fileSystems = t.FileSystems.String()
storage.storagePools = t.StoragePools.String()
storage.volumes = t.Volumes.String()

storage.enclosures = t.Links.Enclosures.ToStrings()
Expand All @@ -254,66 +254,18 @@ func (storage *Storage) UnmarshalJSON(b []byte) error {

// Connection gets the connections that this storage subsystem contains.
func (storage *Storage) Connections() ([]*Connection, error) {
var result []*Connection

collectionError := common.NewCollectionError()
for _, uri := range storage.connections {
item, err := GetConnection(storage.GetClient(), uri)
if err != nil {
collectionError.Failures[uri] = err
} else {
result = append(result, item)
}
}

if collectionError.Empty() {
return result, nil
}

return result, collectionError
return ListReferencedConnections(storage.GetClient(), storage.connections)
}

// ConsistencyGroups gets groups of volumes that are treated as a single resource
// by an application or set of applications.
// func (storage *Storage) ConsistencyGroups() ([]*swordfish.ConsistencyGroup, error) {
// var result []*swordfish.ConsistencyGroup

// collectionError := common.NewCollectionError()
// for _, uri := range storage.consistencyGroups {
// item, err := swordfish.GetConsistencyGroup(storage.GetClient(), uri)
// if err != nil {
// collectionError.Failures[uri] = err
// } else {
// result = append(result, item)
// }
// }

// if collectionError.Empty() {
// return result, nil
// }

// return result, collectionError
// return swordfishListReferencedConsistencyGroups(storage.GetClient(), storage.consistencyGroups)
// }

// Controllers gets the set of storage controllers allocated to this storage subsystem.
func (storage *Storage) Controllers() ([]*StorageController, error) {
var result []*StorageController

collectionError := common.NewCollectionError()
for _, uri := range storage.controllers {
item, err := GetStorageController(storage.GetClient(), uri)
if err != nil {
collectionError.Failures[uri] = err
} else {
result = append(result, item)
}
}

if collectionError.Empty() {
return result, nil
}

return result, collectionError
return ListReferencedStorageControllers(storage.GetClient(), storage.controllers)
}

// Drives gets the drives attached to the storage controllers that this
Expand Down Expand Up @@ -341,67 +293,12 @@ func (storage *Storage) Drives() ([]*Drive, error) {
// EndpointGroups gets the set of endpoints that are used for a common purpose such as an ACL
// or logical identification, that belong to this storage subsystem.
func (storage *Storage) EndpointGroups() ([]*EndpointGroup, error) {
var result []*EndpointGroup

collectionError := common.NewCollectionError()
for _, uri := range storage.endpointGroups {
item, err := GetEndpointGroup(storage.GetClient(), uri)
if err != nil {
collectionError.Failures[uri] = err
} else {
result = append(result, item)
}
}

if collectionError.Empty() {
return result, nil
}

return result, collectionError
return ListReferencedEndpointGroups(storage.GetClient(), storage.endpointGroups)
}

// FileSystems gets the file systems that are allocated by this storage subsystem.
// func (storage *Storage) FileSystems() ([]*swordfish.FileSystem, error) {
// var result []*swordfish.FileSystem

// collectionError := common.NewCollectionError()
// for _, uri := range storage.fileSystems {
// item, err := swordfish.GetFileSystem(storage.GetClient(), uri)
// if err != nil {
// collectionError.Failures[uri] = err
// } else {
// result = append(result, item)
// }
// }

// if collectionError.Empty() {
// return result, nil
// }

// return result, collectionError
// }

// StoragePools gets the storage pools that are allocated by this storage subsystem.
// A storage pool is the set of storage capacity that can be used to produce volumes
// or other storage pools.
// func (storage *Storage) StoragePools() ([]*swordfish.StoragePool, error) {
// var result []*swordfish.StoragePool

// collectionError := common.NewCollectionError()
// for _, uri := range storage.storagePools {
// item, err := swordfish.GetStoragePool(storage.GetClient(), uri)
// if err != nil {
// collectionError.Failures[uri] = err
// } else {
// result = append(result, item)
// }
// }

// if collectionError.Empty() {
// return result, nil
// }

// return result, collectionError
// return swordfish.ListReferencedFileSystems(storage.GetClient(), storage.fileSystems)
// }

// Volumes gets the volumes associated with this storage subsystem.
Expand Down
154 changes: 154 additions & 0 deletions redfish/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,151 @@ var storageBody = `{
}
}`

var storageBodyDell = `{
"@odata.context": "/redfish/v1/$metadata#Storage.Storage",
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1",
"@odata.type": "#Storage.v1_15_0.Storage",
"Controllers": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Controllers"
},
"Description": "Embedded AHCI 1",
"Drives": [],
"Drives@odata.count": 0,
"Id": "AHCI.Embedded.1-1",
"Identifiers": [
{
"DurableName": null,
"DurableNameFormat": null
}
],
"Identifiers@odata.count": 1,
"Links": {
"Enclosures": [
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1"
}
],
"Enclosures@odata.count": 1,
"Oem": {
"Dell": {
"@odata.type": "#DellOem.v1_3_0.DellOemLinks",
"CPUAffinity": [],
"CPUAffinity@odata.count": 0
}
},
"SimpleStorage": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/SimpleStorage/AHCI.Embedded.1-1"
}
},
"Name": "Sapphire Rapids SATA AHCI Controller",
"Oem": {
"Dell": {
"@odata.type": "#DellOem.v1_3_0.DellOemResources",
"DellController": {
"@odata.context": "/redfish/v1/$metadata#DellController.DellController",
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Oem/Dell/DellControllers/AHCI.Embedded.1-1",
"@odata.type": "#DellController.v1_4_1.DellController",
"AlarmState": "AlarmNotPresent",
"AutoConfigBehavior": "NotApplicable",
"BootVirtualDiskFQDD": null,
"CacheSizeInMB": 0,
"CachecadeCapability": "NotSupported",
"ConnectorCount": 0,
"ControllerFirmwareVersion": null,
"CurrentControllerMode": "NotSupported",
"Description": "An instance of DellController will have RAID Controller specific data.",
"Device": "0",
"DeviceCardDataBusWidth": "Unknown",
"DeviceCardSlotLength": "Unknown",
"DeviceCardSlotType": "Unknown",
"DriverVersion": null,
"EncryptionCapability": "None",
"EncryptionMode": "None",
"Id": "AHCI.Embedded.1-1",
"KeyID": null,
"LastSystemInventoryTime": "2024-04-10T22:38:06+00:00",
"LastUpdateTime": "2024-02-20T05:22:02+00:00",
"MaxAvailablePCILinkSpeed": null,
"MaxPossiblePCILinkSpeed": null,
"Name": "DellController",
"PCISlot": null,
"PatrolReadState": "Unknown",
"PersistentHotspare": "NotApplicable",
"RealtimeCapability": "Incapable",
"RollupStatus": "Unknown",
"SASAddress": "0",
"SecurityStatus": "EncryptionNotCapable",
"SharedSlotAssignmentAllowed": "NotApplicable",
"SlicedVDCapability": "NotSupported",
"SupportControllerBootMode": "NotSupported",
"SupportEnhancedAutoForeignImport": "NotSupported",
"SupportRAID10UnevenSpans": "NotSupported",
"SupportsLKMtoSEKMTransition": "No",
"T10PICapability": "NotSupported"
}
}
},
"Status": {
"Health": null,
"HealthRollup": null,
"State": "Enabled"
},
"StorageControllers": [
{
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1#/StorageControllers/0",
"Assembly": {
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/Assembly"
},
"CacheSummary": {
"TotalCacheSizeMiB": 0
},
"ControllerRates": {
"ConsistencyCheckRatePercent": null,
"RebuildRatePercent": null
},
"FirmwareVersion": "",
"Identifiers": [
{
"DurableName": null,
"DurableNameFormat": null
}
],
"Identifiers@odata.count": 1,
"Links": {
"PCIeFunctions": [
{
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/0-24/PCIeFunctions/0-24-0"
}
],
"PCIeFunctions@odata.count": 1
},
"Manufacturer": "DELL",
"MemberId": "0",
"Model": "Sapphire Rapids SATA AHCI Controller",
"Name": "Sapphire Rapids SATA AHCI Controller",
"SpeedGbps": null,
"Status": {
"Health": null,
"HealthRollup": null,
"State": "Enabled"
},
"SupportedControllerProtocols": [
"PCIe"
],
"SupportedControllerProtocols@odata.count": 1,
"SupportedDeviceProtocols": [],
"SupportedDeviceProtocols@odata.count": 0,
"SupportedRAIDTypes": [],
"SupportedRAIDTypes@odata.count": 0
}
],
"StorageControllers@Redfish.Deprecated": "Please migrate to use /redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Controllers",
"StorageControllers@odata.count": 1,
"Volumes": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Storage/AHCI.Embedded.1-1/Volumes"
}
}`

// TestStorage tests the parsing of Storage objects.
func TestStorage(t *testing.T) {
var result Storage
Expand Down Expand Up @@ -159,6 +304,15 @@ func TestStorage(t *testing.T) {
}
}

func TestStorageDell(t *testing.T) {
var result Storage
err := json.NewDecoder(strings.NewReader(storageBodyDell)).Decode(&result)

if err != nil {
t.Errorf("Error decoding JSON: %s", err)
}
}

// TestStorageControllerUpdate tests the Update call.
func TestStorageControllerUpdate(t *testing.T) {
var result Storage
Expand Down
4 changes: 2 additions & 2 deletions redfish/storagecontrollermetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ func GetStorageControllerMetrics(c common.Client, uri string) (*StorageControlle
return &storagecontrollermetrics, nil
}

// ListReferencedStorageControllerMetricss gets the collection of StorageControllerMetrics from
// ListReferencedStorageControllerMetrics gets the collection of StorageControllerMetrics from
// a provided reference.
func ListReferencedStorageControllerMetricss(c common.Client, link string) ([]*StorageControllerMetrics, error) {
func ListReferencedStorageControllerMetrics(c common.Client, link string) ([]*StorageControllerMetrics, error) {
var result []*StorageControllerMetrics
if link == "" {
return result, nil
Expand Down