package detect
import (
"github.com/analogj/scrutiny/collector/pkg/common/shell"
"github.com/analogj/scrutiny/collector/pkg/models"
"github.com/jaypipes/ghw"
"strings"
)
func DevicePrefix ( ) string {
return "/dev/"
}
func ( d * Detect ) Start ( ) ( [ ] models . Device , error ) {
d . Shell = shell . Create ( )
// call the base/common functionality to get a list of devicess
detectedDevices , err := d . SmartctlScan ( )
if err != nil {
return nil , err
}
//smartctl --scan doesn't seem to detect mac nvme drives, lets see if we can detect them manually.
missingDevices , err := d . findMissingDevices ( detectedDevices ) //we dont care about the error here, just continue retrieving device info.
if err == nil {
detectedDevices = append ( detectedDevices , missingDevices ... )
}
//inflate device info for detected devices.
for ndx , _ := range detectedDevices {
d . SmartCtlInfo ( & detectedDevices [ ndx ] ) //ignore errors.
}
return detectedDevices , nil
}
func ( d * Detect ) findMissingDevices ( detectedDevices [ ] models . Device ) ( [ ] models . Device , error ) {
missingDevices := [ ] models . Device { }
block , err := ghw . Block ( )
if err != nil {
d . Logger . Errorf ( "Error getting block storage info: %v" , err )
return nil , err
}
for _ , disk := range block . Disks {
// ignore optical drives and floppy disks
if disk . DriveType == ghw . DRIVE_TYPE_FDD || disk . DriveType == ghw . DRIVE_TYPE_ODD {
d . Logger . Debugf ( " => Ignore: Optical or floppy disk - (found %s)\n" , disk . DriveType . String ( ) )
continue
}
// ignore removable disks
if disk . IsRemovable {
d . Logger . Debugf ( " => Ignore: Removable disk (%v)\n" , disk . IsRemovable )
continue
}
// ignore virtual disks & mobile phone storage devices
if disk . StorageController == ghw . STORAGE_CONTROLLER_VIRTIO || disk . StorageController == ghw . STORAGE_CONTROLLER_MMC {
d . Logger . Debugf ( " => Ignore: Virtual/multi-media storage controller - (found %s)\n" , disk . StorageController . String ( ) )
continue
}
// Skip unknown storage controllers, not usually S.M.A.R.T compatible.
if disk . StorageController == ghw . STORAGE_CONTROLLER_UNKNOWN {
d . Logger . Debugf ( " => Ignore: Unknown storage controller - (found %s)\n" , disk . StorageController . String ( ) )
continue
}
//check if device is already detected.
alreadyDetected := false
diskName := strings . TrimPrefix ( disk . Name , DevicePrefix ( ) )
for _ , detectedDevice := range detectedDevices {
if detectedDevice . DeviceName == diskName {
alreadyDetected = true
break
}
}
if ! alreadyDetected {
missingDevices = append ( missingDevices , models . Device {
DeviceName : diskName ,
DeviceType : "" ,
} )
}
}
return missingDevices , nil
}
//WWN values NVMe and SCSI
func ( d * Detect ) wwnFallback ( detectedDevice * models . Device ) {
block , err := ghw . Block ( )
if err == nil {
for _ , disk := range block . Disks {
if disk . Name == detectedDevice . DeviceName && strings . ToLower ( disk . WWN ) != "unknown" {
d . Logger . Debugf ( "Found matching block device. WWN: %s" , disk . WWN )
detectedDevice . WWN = disk . WWN
break
}
}
}
//no WWN found, or could not open Block devices. Either way, fallback to serial number
if len ( detectedDevice . WWN ) == 0 {
d . Logger . Debugf ( "WWN is empty, falling back to serial number: %s" , detectedDevice . SerialNumber )
detectedDevice . WWN = detectedDevice . SerialNumber
}
//wwn must always be lowercase.
detectedDevice . WWN = strings . ToLower ( detectedDevice . WWN )
}