fw_dut_info: populate setters

Populates the setters (with the exception of the phase attribute).
Additionally refines some names of storage related fields for
consistency with the other fields, and defines and utilizes a
constructor for new variables of type dut.

BUG=b:141394343
TEST=emerged, ran, and inspected output

Change-Id: I5452b529dac28f96479b9cf35648dc39c3304b40
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crostestutils/+/2079918
Tested-by: Kevin Shelton <kmshelton@chromium.org>
Reviewed-by: Greg Edelston <gredelston@google.com>
Commit-Queue: Kevin Shelton <kmshelton@chromium.org>
Auto-Submit: Kevin Shelton <kmshelton@chromium.org>
diff --git a/go/src/firmware/cmd/dut_info/fw_dut_info.go b/go/src/firmware/cmd/dut_info/fw_dut_info.go
index 0c1ecca..bb69f5b 100644
--- a/go/src/firmware/cmd/dut_info/fw_dut_info.go
+++ b/go/src/firmware/cmd/dut_info/fw_dut_info.go
@@ -7,53 +7,231 @@
 import (
 	"firmware/internal/pkg/dutio"
 	"fmt"
-	"log"
 )
 
 // TODO(kmshelton): Move the dut definition into the dutio package and make SendSSHCommand a method on dut.
 type dut struct {
-	hostname     string
-	phase        string
-	crosVersion  string
-	biosVersion  string
-	ecROVersion  string
-	ecRWVersion  string
-	gscVersion   string
-	cpuArch      string
-	cpuModel     string
-	cpuSpeed     string
-	totalMemory  string
-	memoryType   string
-	mmcModel     string
-	mmcFirmware  string
-	nvmeModel    string
-	nvmeFirmware string
-	vpd          string
+	hostname            string
+	model               string
+	phase               string
+	crOSVersion         string
+	biosVersion         string
+	ecROVersion         string
+	ecRWVersion         string
+	gscVersion          string
+	cpuArch             string
+	cpuModel            string
+	cpuSpeed            string
+	totalMemory         string
+	memoryType          string
+	mmcModel            string
+	mmcFirmwareVersion  string
+	nvmeModel           string
+	nvmeFirmwareVersion string
+	vpd                 string
 }
 
-// setCPUSpeed interfaces with a DUT and sets the cpuSpeed field (the clock frequency of the central processing unit).
-func (d *dut) setCPUSpeed() error {
-	// TODO(kmshelton): Use dbus instead of executing commands directly on the DUT.
-	// This is only a temporary command to support incremental development.
+// setModel interfaces with a DUT and sets the model field (the DUT's market identifier).
+func (d *dut) setModel() error {
+	// TODO(kmshelton): Here and elsewhere: use dbus instead of executing commands directly
+	// on the DUT (by exposing such functionality in dutio).
+	out, err := dutio.SendSSHCommand(d.hostname, "cros_config / name")
+	if err != nil {
+		return err
+	}
+	// TODO(kmshelton): Add some validation on out (here and elsewhere).
+	d.model = out
+	return nil
+}
+
+// setPhase interfaces with a DUT and sets the phase field (the DUT's hardware stage).
+func (d *dut) setPhase() error {
+	// Phase is not implemented in dut.sh (which this utility replaces), likely because
+	// getting phase involves interfacing with the HWID database.
+	// TODO(b:150699151): Implement this setter (interface with the HWID database).
+	d.phase = ""
+	return nil
+}
+
+// setCrOSVersion interfaces with a DUT and sets the crOSVersion field (the DUT's version of ChromeOS).
+func (d *dut) setCrOSVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "grep '^CHROMEOS_RELEASE_DESCRIPTION=' /etc/lsb-release | cut -d= -f2")
+	if err != nil {
+		return err
+	}
+	d.crOSVersion = out
+	return nil
+}
+
+// setBIOSVersion interfaces with a DUT and sets the biosVersion field (the DUT's application processor firmware version).
+func (d *dut) setBIOSVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "echo $(crossystem ro_fwid) / $(crossystem fwid)")
+	if err != nil {
+		return err
+	}
+	d.biosVersion = out
+	return nil
+}
+
+// setECROVersion interfaces with a DUT and sets the ecROVersion field (the version of the DUT's read-only copy of the primary
+// embedded controller's firmware version).
+func (d *dut) setECROVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "ectool version | awk '/^RO/{print $3}'")
+	if err != nil {
+		return err
+	}
+	d.ecROVersion = out
+	return nil
+}
+
+// setECRWVersion interfaces with a DUT and sets the ecRWVersion field (the version of the DUT's read-write copy of the primary
+// embedded controller's firmware version).
+func (d *dut) setECRWVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "ectool version | awk '/^RW/{print $3}'")
+	if err != nil {
+		return err
+	}
+	d.ecRWVersion = out
+	return nil
+}
+
+// setGSCVersion interfaces with a DUT and sets the gscVersion field (the version of the DUT's Google Security Chip firmware).
+func (d *dut) setGSCVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "echo $(grep ^RO /var/cache/cr50-version) / $(grep ^RW /var/cache/cr50-version)")
+	if err != nil {
+		return err
+	}
+	d.gscVersion = out
+	return nil
+}
+
+// setCPUArch interfaces with a DUT and sets the cpuArch field (the architecture of the central processing unit).
+func (d *dut) setCPUArch() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "lscpu | awk '/^Architecture:/{print $2}'")
+	if err != nil {
+		return err
+	}
+	d.cpuArch = out
+	return nil
+}
+
+// setCPUModel interfaces with a DUT and sets the cpuModel field (the market identifier of the central processing unit).
+func (d *dut) setCPUModel() error {
 	out, err := dutio.SendSSHCommand(d.hostname, "lscpu | grep '^Model name:' | cut -d: -f2-")
 	if err != nil {
 		return err
 	}
-	// TODO(kmshelton): Add some validation on out.
 	d.cpuModel = out
-	return err
+	return nil
+}
+
+// setCPUSpeed interfaces with a DUT and sets the cpuSpeed field (the clock frequency of the central processing unit).
+func (d *dut) setCPUSpeed() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "lscpu | grep '^CPU max MHz:' | cut -d: -f2-")
+	if err != nil {
+		return err
+	}
+	d.cpuSpeed = out
+	return nil
+}
+
+// setTotalMemory interfaces with a DUT and sets the totalMemory field (the size of the main memory).
+func (d *dut) setTotalMemory() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "grep '^MemTotal:' /proc/meminfo 2>/dev/null | cut -d: -f2-")
+	if err != nil {
+		return err
+	}
+	d.totalMemory = out
+	return nil
+}
+
+// setMemoryType interfaces with a DUT and sets the memoryType field (the technology class of the main memory).
+func (d *dut) setMemoryType() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "mosys memory spd print id 2>/dev/null | cut -d'|' -f2- | sort -u")
+	if err != nil {
+		return err
+	}
+	d.memoryType = out
+	return nil
+}
+
+// setMMCModel interfaces with a DUT and sets the mmcModel field (the multimedia card market identifier).
+func (d *dut) setMMCModel() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "if [ -e /dev/mmcblk ]; then cat /dev/mmcblk/device/name; else true; fi")
+	if err != nil {
+		return err
+	}
+	d.mmcModel = out
+	return nil
+}
+
+// setMMCFirmwareVersion interfaces with a DUT and sets the version of the multimedia card's firmware.
+func (d *dut) setMMCFirmwareVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "if [ -e /dev/mmcblk ]; then cat /dev/mmcblk/device/firmware; else true; fi")
+	if err != nil {
+		return err
+	}
+	d.mmcFirmwareVersion = out
+	return nil
+}
+
+// setNVMEModel interfaces with a DUT and sets the nvmeModel (the market identifier of the non-volatile memory express solid state drive).
+func (d *dut) setNVMEModel() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "if [ -e /dev/nvme0n1 ]; then cat /dev/nvme0n1/device/name; else true; fi")
+	if err != nil {
+		return err
+	}
+	d.nvmeModel = out
+	return nil
+}
+
+// setNVMEFirmwareVersion interfaces with a DUT and sets the nvmeFirmwareVersion field (the firmware version of the non-volatile
+//  memory express solid state drive).
+func (d *dut) setNVMEFirmwareVersion() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "if [ -e /dev/nvme0n1 ]; then cat /dev/nvme0n1/device/fwrev; else true; fi")
+	if err != nil {
+		return err
+	}
+	d.nvmeFirmwareVersion = out
+	return nil
+}
+
+// setVPD interfaces with a DUT and sets the vpd field (the "Vital Product Data").
+func (d *dut) setVPD() error {
+	out, err := dutio.SendSSHCommand(d.hostname, "vpd -l")
+	if err != nil {
+		return err
+	}
+	d.vpd = out
+	return nil
+}
+
+// newDUT initializes all the fields in a dut struct.
+func newDUT(hostname string) dut {
+	d := dut{hostname: hostname}
+	d.setModel()
+	d.setPhase()
+	d.setCrOSVersion()
+	d.setBIOSVersion()
+	d.setECROVersion()
+	d.setECRWVersion()
+	d.setGSCVersion()
+	d.setCPUArch()
+	d.setCPUModel()
+	d.setCPUSpeed()
+	d.setTotalMemory()
+	d.setMemoryType()
+	d.setMMCModel()
+	d.setMMCFirmwareVersion()
+	d.setNVMEModel()
+	d.setNVMEFirmwareVersion()
+	d.setVPD()
+	return d
 }
 
 func main() {
 	fmt.Println("This utility is undergoing incremental development.  Please use crostestutils/provingground/firmware/dut.sh for now.")
-	// TODO(kmshelton): Expose the same functionality as crostestutils/provingground/firmware/dut.sh.
-	// The functionality in dut.sh is determining properties of the DUT like various firmware versions,
-	// which will be added to this utility.
 	// TODO(kmshelton): Unhardcode the hostname.
-	d := dut{hostname: "chromeos1-row1-rack8-host2.cros.corp.google.com"}
-	err := d.setCPUSpeed()
-	if err != nil {
-		log.Panic(err)
-	}
-	fmt.Println(d)
+	d := newDUT("chromeos1-row1-rack8-host2.cros.corp.google.com")
+	fmt.Printf("%+v\n", d)
 }