ghw

package module
v0.5.1-0...-5e0fb8e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 24, 2020 License: Apache-2.0 Imports: 17 Imported by: 0

README

ghw - Golang HardWare discovery/inspection library Build Status

ghw mascot

ghw is a small Golang library providing hardware inspection and discovery for Linux. There currently exists partial support for MacOSX and Windows support is planned for a future release.

Design Principles

  • No root privileges needed for discovery

    ghw goes the extra mile to be useful without root priveleges. We query for host hardware information as directly as possible without relying on shellouts to programs like dmidecode that require root privileges to execute.

    Elevated privileges are indeed required to query for some information, but ghw will never error out if blocked from reading that information. Instead, ghw will print a warning message about the information that could not be retrieved. You may disable these warning messages with GHW_DISABLE_WARNINGS environment variable.

  • Well-documented code and plenty of example code

    The code itself should be well-documented with lots of usage examples.

  • Interfaces should be consistent across modules

    Each module in the library should be structured in a consistent fashion, and the structs returned by various library functions should have consistent attribute and method names.

Usage

You can use the functions in ghw to determine various hardware-related information about the host computer:

Overriding the root mountpoint ghw uses

The default root mountpoint that ghw uses when looking for information about the host system is /. So, for example, when looking up CPU information on a Linux system, ghw.CPU() will use the path /proc/cpuinfo.

If you are calling ghw from a system that has an alternate root mountpoint, you can either set the GHW_CHROOT environment variable to that alternate path, or call the module constructor function with the ghw.WithChroot() modifier.

For example, if you are executing from within an application container that has bind-mounted the root host filesystem to the mount point /host, you would set GHW_CHROOT to /host so that ghw can find /proc/cpuinfo at /host/proc/cpuinfo.

Alternately, you can use the ghw.WithChroot() function like so:

cpu, err := ghw.CPU(ghw.WithChroot("/host"))
Disabling warning messages

When ghw isn't able to retrieve some information, it may print certain warning messages to stderr. To disable these warnings, simply set the GHW_DISABLE_WARNINGS environs variable:

$ ghwc memory
WARNING:
Could not determine total physical bytes of memory. This may
be due to the host being a virtual machine or container with no
/var/log/syslog file, or the current user may not have necessary
privileges to read the syslog. We are falling back to setting the
total physical amount of memory to the total usable amount of memory
memory (24GB physical, 24GB usable)
$ GHW_DISABLE_WARNINGS=1 ghwc memory
memory (24GB physical, 24GB usable)
Memory

Information about the host computer's memory can be retrieved using the ghw.Memory() function which returns a pointer to a ghw.MemoryInfo struct.

The ghw.MemoryInfo struct contains three fields:

  • ghw.MemoryInfo.TotalPhysicalBytes contains the amount of physical memory on the host
  • ghw.MemoryInfo.TotalUsableBytes contains the amount of memory the system can actually use. Usable memory accounts for things like the kernel's resident memory size and some reserved system bits
  • ghw.MemoryInfo.SupportedPageSizes is an array of integers representing the size, in bytes, of memory pages the system supports
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	memory, err := ghw.Memory()
	if err != nil {
		fmt.Printf("Error getting memory info: %v", err)
	}

	fmt.Println(memory.String())
}

Example output from my personal workstation:

memory (24GB physical, 24GB usable)
CPU

The ghw.CPU() function returns a ghw.CPUInfo struct that contains information about the CPUs on the host system.

ghw.CPUInfo contains the following fields:

  • ghw.CPUInfo.TotalCores has the total number of physical cores the host system contains
  • ghw.CPUInfo.TotalThreads has the total number of hardware threads the host system contains
  • ghw.CPUInfo.Processors is an array of ghw.Processor structs, one for each physical processor package contained in the host

Each ghw.Processor struct contains a number of fields:

  • ghw.Processor.ID is the physical processor uint32 ID according to the system
  • ghw.Processor.NumCores is the number of physical cores in the processor package
  • ghw.Processor.NumThreads is the number of hardware threads in the processor package
  • ghw.Processor.Vendor is a string containing the vendor name
  • ghw.Processor.Model is a string containing the vendor's model name
  • ghw.Processor.Capabilities is an array of strings indicating the features the processor has enabled
  • ghw.Processor.Cores is an array of ghw.ProcessorCore structs that are packed onto this physical processor

A ghw.ProcessorCore has the following fields:

  • ghw.ProcessorCore.ID is the uint32 identifier that the host gave this core. Note that this does not necessarily equate to a zero-based index of the core within a physical package. For example, the core IDs for an Intel Core i7 are 0, 1, 2, 8, 9, and 10
  • ghw.ProcessorCore.Index is the zero-based index of the core on the physical processor package
  • ghw.ProcessorCore.NumThreads is the number of hardware threads associated with the core
  • ghw.ProcessorCore.LogicalProcessors is an array of logical processor IDs assigned to any processing unit for the core
package main

import (
	"fmt"
	"math"
	"strings"

	"github.com/jaypipes/ghw"
)

func main() {
	cpu, err := ghw.CPU()
	if err != nil {
		fmt.Printf("Error getting CPU info: %v", err)
	}

	fmt.Printf("%v\n", cpu)

	for _, proc := range cpu.Processors {
		fmt.Printf(" %v\n", proc)
		for _, core := range proc.Cores {
			fmt.Printf("  %v\n", core)
		}
		if len(proc.Capabilities) > 0 {
			// pretty-print the (large) block of capability strings into rows
			// of 6 capability strings
			rows := int(math.Ceil(float64(len(proc.Capabilities)) / float64(6)))
			for row := 1; row < rows; row = row + 1 {
				rowStart := (row * 6) - 1
				rowEnd := int(math.Min(float64(rowStart+6), float64(len(proc.Capabilities))))
				rowElems := proc.Capabilities[rowStart:rowEnd]
				capStr := strings.Join(rowElems, " ")
				if row == 1 {
					fmt.Printf("  capabilities: [%s\n", capStr)
				} else if rowEnd < len(proc.Capabilities) {
					fmt.Printf("                 %s\n", capStr)
				} else {
					fmt.Printf("                 %s]\n", capStr)
				}
			}
		}
	}
}

Example output from my personal workstation:

cpu (1 physical package, 6 cores, 12 hardware threads)
 physical package #0 (6 cores, 12 hardware threads)
  processor core #0 (2 threads), logical processors [0 6]
  processor core #1 (2 threads), logical processors [1 7]
  processor core #2 (2 threads), logical processors [2 8]
  processor core #3 (2 threads), logical processors [3 9]
  processor core #4 (2 threads), logical processors [4 10]
  processor core #5 (2 threads), logical processors [5 11]
  capabilities: [msr pae mce cx8 apic sep
                 mtrr pge mca cmov pat pse36
                 clflush dts acpi mmx fxsr sse
                 sse2 ss ht tm pbe syscall
                 nx pdpe1gb rdtscp lm constant_tsc arch_perfmon
                 pebs bts rep_good nopl xtopology nonstop_tsc
                 cpuid aperfmperf pni pclmulqdq dtes64 monitor
                 ds_cpl vmx est tm2 ssse3 cx16
                 xtpr pdcm pcid sse4_1 sse4_2 popcnt
                 aes lahf_lm pti retpoline tpr_shadow vnmi
                 flexpriority ept vpid dtherm ida arat]
Block storage

Information about the host computer's local block storage is returned from the ghw.Block() function. This function returns a pointer to a ghw.BlockInfo struct.

The ghw.BlockInfo struct contains two fields:

  • ghw.BlockInfo.TotalPhysicalBytes contains the amount of physical block storage on the host
  • ghw.BlockInfo.Disks is an array of pointers to ghw.Disk structs, one for each disk drive found by the system

Each ghw.Disk struct contains the following fields:

  • ghw.Disk.Name contains a string with the short name of the disk, e.g. "sda"
  • ghw.Disk.SizeBytes contains the amount of storage the disk provides
  • ghw.Disk.PhysicalBlockSizeBytes contains the size of the physical blocks used on the disk, in bytes
  • ghw.Disk.DriveType is the type of drive. It is of type ghw.DriveType which has a ghw.DriveType.String() method that can be called to return a string representation of the bus. This string will be "HDD", "FDD", "ODD", or "SSD", which correspond to a hard disk drive (rotational), floppy drive, optical (CD/DVD) drive and solid-state drive.
  • ghw.Disk.StorageController is the type of storage controller/drive. It is of type ghw.StorageController which has a ghw.StorageController.String() method that can be called to return a string representation of the bus. This string will be "SCSI", "IDE", "virtio", "MMC", or "NVMe"
  • ghw.Disk.NUMANodeID is the numeric index of the NUMA node this disk is local to, or -1
  • ghw.Disk.Vendor contains a string with the name of the hardware vendor for the disk drive
  • ghw.Disk.Model contains a string with the vendor-assigned disk model name
  • ghw.Disk.SerialNumber contains a string with the disk's serial number
  • ghw.Disk.WWN contains a string with the disk's World Wide Name
  • ghw.Disk.Partitions contains an array of pointers to ghw.Partition structs, one for each partition on the disk

Each ghw.Partition struct contains these fields:

  • ghw.Partition.Name contains a string with the short name of the partition, e.g. "sda1"
  • ghw.Partition.SizeBytes contains the amount of storage the partition provides
  • ghw.Partition.MountPoint contains a string with the partition's mount point, or "" if no mount point was discovered
  • ghw.Partition.Type contains a string indicated the filesystem type for the partition, or "" if the system could not determine the type
  • ghw.Partition.IsReadOnly is a bool indicating the partition is read-only
  • ghw.Partition.Disk is a pointer to the ghw.Disk object associated with the partition. This will be nil if the ghw.Partition struct was returned by the ghw.DiskPartitions() library function.
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	block, err := ghw.Block()
	if err != nil {
		fmt.Printf("Error getting block storage info: %v", err)
	}

	fmt.Printf("%v\n", block)

	for _, disk := range block.Disks {
		fmt.Printf(" %v\n", disk)
		for _, part := range disk.Partitions {
			fmt.Printf("  %v\n", part)
		}
	}
}

Example output from my personal workstation:

block storage (1 disk, 2TB physical storage)
 /dev/sda HDD (2TB) SCSI [@pci-0000:04:00.0-scsi-0:1:0:0 (node #0)] vendor=LSI model=Logical_Volume serial=600508e000000000f8253aac9a1abd0c WWN=0x600508e000000000f8253aac9a1abd0c
  /dev/sda1 (100MB)
  /dev/sda2 (187GB)
  /dev/sda3 (449MB)
  /dev/sda4 (1KB)
  /dev/sda5 (15GB)
  /dev/sda6 (2TB) [ext4] mounted@/

Note that ghw looks in the udev runtime database for some information. If you are using ghw in a container, remember to bind mount /dev/disk and /run into your container, otherwise ghw won't be able to query the udev DB or sysfs paths for information.

Topology

Information about the host computer's architecture (NUMA vs. SMP), the host's node layout and processor caches can be retrieved from the ghw.Topology() function. This function returns a pointer to a ghw.TopologyInfo struct.

The ghw.TopologyInfo struct contains two fields:

  • ghw.TopologyInfo.Architecture contains an enum with the value ghw.NUMA or ghw.SMP depending on what the topology of the system is
  • ghw.TopologyInfo.Nodes is an array of pointers to ghw.TopologyNode structs, one for each topology node (typically physical processor package) found by the system

Each ghw.TopologyNode struct contains the following fields:

  • ghw.TopologyNode.ID is the system's uint32 identifier for the node
  • ghw.TopologyNode.Cores is an array of pointers to ghw.ProcessorCore structs that are contained in this node
  • ghw.TopologyNode.Caches is an array of pointers to ghw.MemoryCache structs that represent the low-level caches associated with processors and cores on the system

See above in the CPU section for information about the ghw.ProcessorCore struct and how to use and query it.

Each ghw.MemoryCache struct contains the following fields:

  • ghw.MemoryCache.Type is an enum that contains one of ghw.DATA, ghw.INSTRUCTION or ghw.UNIFIED depending on whether the cache stores CPU instructions, program data, or both
  • ghw.MemoryCache.Level is a positive integer indicating how close the cache is to the processor
  • ghw.MemoryCache.SizeBytes is an integer containing the number of bytes the cache can contain
  • ghw.MemoryCache.LogicalProcessors is an array of integers representing the logical processors that use the cache
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	topology, err := ghw.Topology()
	if err != nil {
		fmt.Printf("Error getting topology info: %v", err)
	}

	fmt.Printf("%v\n", topology)

	for _, node := range topology.Nodes {
		fmt.Printf(" %v\n", node)
		for _, cache := range node.Caches {
			fmt.Printf("  %v\n", cache)
		}
	}
}

Example output from my personal workstation:

topology SMP (1 nodes)
 node #0 (6 cores)
  L1i cache (32 KB) shared with logical processors: 3,9
  L1i cache (32 KB) shared with logical processors: 2,8
  L1i cache (32 KB) shared with logical processors: 11,5
  L1i cache (32 KB) shared with logical processors: 10,4
  L1i cache (32 KB) shared with logical processors: 0,6
  L1i cache (32 KB) shared with logical processors: 1,7
  L1d cache (32 KB) shared with logical processors: 11,5
  L1d cache (32 KB) shared with logical processors: 10,4
  L1d cache (32 KB) shared with logical processors: 3,9
  L1d cache (32 KB) shared with logical processors: 1,7
  L1d cache (32 KB) shared with logical processors: 0,6
  L1d cache (32 KB) shared with logical processors: 2,8
  L2 cache (256 KB) shared with logical processors: 2,8
  L2 cache (256 KB) shared with logical processors: 3,9
  L2 cache (256 KB) shared with logical processors: 0,6
  L2 cache (256 KB) shared with logical processors: 10,4
  L2 cache (256 KB) shared with logical processors: 1,7
  L2 cache (256 KB) shared with logical processors: 11,5
  L3 cache (12288 KB) shared with logical processors: 0,1,10,11,2,3,4,5,6,7,8,9
Network

Information about the host computer's networking hardware is returned from the ghw.Network() function. This function returns a pointer to a ghw.NetworkInfo struct.

The ghw.NetworkInfo struct contains one field:

  • ghw.NetworkInfo.NICs is an array of pointers to ghw.NIC structs, one for each network interface controller found for the systen

Each ghw.NIC struct contains the following fields:

  • ghw.NIC.Name is the system's identifier for the NIC
  • ghw.NIC.MacAddress is the MAC address for the NIC, if any
  • ghw.NIC.IsVirtual is a boolean indicating if the NIC is a virtualized device
  • ghw.NIC.Capabilities is an array of pointers to ghw.NICCapability structs that can describe the things the NIC supports. These capabilities match the returned values from the ethtool -k <DEVICE> call on Linux

The ghw.NICCapability struct contains the following fields:

  • ghw.NICCapability.Name is the string name of the capability (e.g. "tcp-segmentation-offload")
  • ghw.NICCapability.IsEnabled is a boolean indicating whether the capability is currently enabled/active on the NIC
  • ghw.NICCapability.CanEnable is a boolean indicating whether the capability may be enabled
package main

import (
    "fmt"

    "github.com/jaypipes/ghw"
)

func main() {
    net, err := ghw.Network()
    if err != nil {
        fmt.Printf("Error getting network info: %v", err)
    }

    fmt.Printf("%v\n", net)

    for _, nic := range net.NICs {
        fmt.Printf(" %v\n", nic)

        enabledCaps := make([]int, 0)
        for x, cap := range nic.Capabilities {
            if cap.IsEnabled {
                enabledCaps = append(enabledCaps, x)
            }
        }
        if len(enabledCaps) > 0 {
            fmt.Printf("  enabled capabilities:\n")
            for _, x := range enabledCaps {
                fmt.Printf("   - %s\n", nic.Capabilities[x].Name)
            }
        }
    }
}

Example output from my personal laptop:

net (3 NICs)
 docker0
  enabled capabilities:
   - tx-checksumming
   - tx-checksum-ip-generic
   - scatter-gather
   - tx-scatter-gather
   - tx-scatter-gather-fraglist
   - tcp-segmentation-offload
   - tx-tcp-segmentation
   - tx-tcp-ecn-segmentation
   - tx-tcp-mangleid-segmentation
   - tx-tcp6-segmentation
   - udp-fragmentation-offload
   - generic-segmentation-offload
   - generic-receive-offload
   - tx-vlan-offload
   - highdma
   - tx-lockless
   - netns-local
   - tx-gso-robust
   - tx-fcoe-segmentation
   - tx-gre-segmentation
   - tx-gre-csum-segmentation
   - tx-ipxip4-segmentation
   - tx-ipxip6-segmentation
   - tx-udp_tnl-segmentation
   - tx-udp_tnl-csum-segmentation
   - tx-gso-partial
   - tx-sctp-segmentation
   - tx-esp-segmentation
   - tx-vlan-stag-hw-insert
 enp58s0f1
  enabled capabilities:
   - rx-checksumming
   - generic-receive-offload
   - rx-vlan-offload
   - tx-vlan-offload
   - highdma
 wlp59s0
  enabled capabilities:
   - scatter-gather
   - tx-scatter-gather
   - generic-segmentation-offload
   - generic-receive-offload
   - highdma
   - netns-local
PCI

ghw contains a PCI database inspection and querying facility that allows developers to not only gather information about devices on a local PCI bus but also query for information about hardware device classes, vendor and product information.

NOTE: Parsing of the PCI-IDS file database is provided by the separate github.com/jaypipes/pcidb library. You can read that library's README for more information about the various structs that are exposed on the ghw.PCIInfo struct.

The ghw.PCI() function returns a ghw.PCIInfo struct. The ghw.PCIInfo struct contains a number of fields that may be queried for PCI information:

  • ghw.PCIInfo.Classes is a map, keyed by the PCI class ID (a hex-encoded string) of pointers to pcidb.Class structs, one for each class of PCI device known to ghw
  • ghw.PCIInfo.Vendors is a map, keyed by the PCI vendor ID (a hex-encoded string) of pointers to pcidb.Vendor structs, one for each PCI vendor known to ghw
  • ghw.PCIInfo.Products is a map, keyed by the PCI product ID* (a hex-encoded string) of pointers to pcidb.Product structs, one for each PCI product known to ghw

NOTE: PCI products are often referred to by their "device ID". We use the term "product ID" in ghw because it more accurately reflects what the identifier is for: a specific product line produced by the vendor.

Listing and accessing host PCI device information

In addition to the above information, the ghw.PCIInfo struct has the following methods:

  • ghw.PCIInfo.ListDevices() []*PCIDevice
  • ghw.PCIInfo.GetDevice(address string) *PCIDevice

This methods return either an array of or a single pointer to a ghw.PCIDevice struct, which has the following fields:

  • ghw.PCIDevice.Vendor is a pointer to a pcidb.Vendor struct that describes the device's primary vendor. This will always be non-nil.
  • ghw.PCIDevice.Product is a pointer to a pcidb.Product struct that describes the device's primary product. This will always be non-nil.
  • ghw.PCIDevice.Subsystem is a pointer to a pcidb.Product struct that describes the device's secondary/sub-product. This will always be non-nil.
  • ghw.PCIDevice.Class is a pointer to a pcidb.Class struct that describes the device's class. This will always be non-nil.
  • ghw.PCIDevice.Subclass is a pointer to a pcidb.Subclass struct that describes the device's subclass. This will always be non-nil.
  • ghw.PCIDevice.ProgrammingInterface is a pointer to a pcidb.ProgrammingInterface struct that describes the device subclass' programming interface. This will always be non-nil.

The following code snippet shows how to call the ghw.PCIInfo.ListDevices() method and output a simple list of PCI address and vendor/product information:

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	pci, err := ghw.PCI()
	if err != nil {
		fmt.Printf("Error getting PCI info: %v", err)
	}
	fmt.Printf("host PCI devices:\n")
	fmt.Println("====================================================")
	devices := pci.ListDevices()
	if len(devices) == 0 {
		fmt.Printf("error: could not retrieve PCI devices\n")
		return
	}

	for _, device := range devices {
		vendor := device.Vendor
		vendorName := vendor.Name
		if len(vendor.Name) > 20 {
			vendorName = string([]byte(vendorName)[0:17]) + "..."
		}
		product := device.Product
		productName := product.Name
		if len(product.Name) > 40 {
			productName = string([]byte(productName)[0:37]) + "..."
		}
		fmt.Printf("%-12s\t%-20s\t%-40s\n", device.Address, vendorName, productName)
	}
}

on my local workstation the output of the above looks like the following:

host PCI devices:
====================================================
0000:00:00.0	Intel Corporation   	5520/5500/X58 I/O Hub to ESI Port
0000:00:01.0	Intel Corporation   	5520/5500/X58 I/O Hub PCI Express Roo...
0000:00:02.0	Intel Corporation   	5520/5500/X58 I/O Hub PCI Express Roo...
0000:00:03.0	Intel Corporation   	5520/5500/X58 I/O Hub PCI Express Roo...
0000:00:07.0	Intel Corporation   	5520/5500/X58 I/O Hub PCI Express Roo...
0000:00:10.0	Intel Corporation   	7500/5520/5500/X58 Physical and Link ...
0000:00:10.1	Intel Corporation   	7500/5520/5500/X58 Routing and Protoc...
0000:00:14.0	Intel Corporation   	7500/5520/5500/X58 I/O Hub System Man...
0000:00:14.1	Intel Corporation   	7500/5520/5500/X58 I/O Hub GPIO and S...
0000:00:14.2	Intel Corporation   	7500/5520/5500/X58 I/O Hub Control St...
0000:00:14.3	Intel Corporation   	7500/5520/5500/X58 I/O Hub Throttle R...
0000:00:19.0	Intel Corporation   	82567LF-2 Gigabit Network Connection
0000:00:1a.0	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1a.1	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1a.2	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1a.7	Intel Corporation   	82801JI (ICH10 Family) USB2 EHCI Cont...
0000:00:1b.0	Intel Corporation   	82801JI (ICH10 Family) HD Audio Contr...
0000:00:1c.0	Intel Corporation   	82801JI (ICH10 Family) PCI Express Ro...
0000:00:1c.1	Intel Corporation   	82801JI (ICH10 Family) PCI Express Po...
0000:00:1c.4	Intel Corporation   	82801JI (ICH10 Family) PCI Express Ro...
0000:00:1d.0	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1d.1	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1d.2	Intel Corporation   	82801JI (ICH10 Family) USB UHCI Contr...
0000:00:1d.7	Intel Corporation   	82801JI (ICH10 Family) USB2 EHCI Cont...
0000:00:1e.0	Intel Corporation   	82801 PCI Bridge
0000:00:1f.0	Intel Corporation   	82801JIR (ICH10R) LPC Interface Contr...
0000:00:1f.2	Intel Corporation   	82801JI (ICH10 Family) SATA AHCI Cont...
0000:00:1f.3	Intel Corporation   	82801JI (ICH10 Family) SMBus Controller
0000:01:00.0	NEC Corporation     	uPD720200 USB 3.0 Host Controller
0000:02:00.0	Marvell Technolog...	88SE9123 PCIe SATA 6.0 Gb/s controller
0000:02:00.1	Marvell Technolog...	88SE912x IDE Controller
0000:03:00.0	NVIDIA Corporation  	GP107 [GeForce GTX 1050 Ti]
0000:03:00.1	NVIDIA Corporation  	UNKNOWN
0000:04:00.0	LSI Logic / Symbi...	SAS2004 PCI-Express Fusion-MPT SAS-2 ...
0000:06:00.0	Qualcomm Atheros    	AR5418 Wireless Network Adapter [AR50...
0000:08:03.0	LSI Corporation     	FW322/323 [TrueFire] 1394a Controller
0000:3f:00.0	Intel Corporation   	UNKNOWN
0000:3f:00.1	Intel Corporation   	Xeon 5600 Series QuickPath Architectu...
0000:3f:02.0	Intel Corporation   	Xeon 5600 Series QPI Link 0
0000:3f:02.1	Intel Corporation   	Xeon 5600 Series QPI Physical 0
0000:3f:02.2	Intel Corporation   	Xeon 5600 Series Mirror Port Link 0
0000:3f:02.3	Intel Corporation   	Xeon 5600 Series Mirror Port Link 1
0000:3f:03.0	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:03.1	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:03.4	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:04.0	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:04.1	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:04.2	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:04.3	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:05.0	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:05.1	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:05.2	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:05.3	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:06.0	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:06.1	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:06.2	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...
0000:3f:06.3	Intel Corporation   	Xeon 5600 Series Integrated Memory Co...

The following code snippet shows how to call the ghw.PCIInfo.GetDevice() method and use its returned ghw.PCIDevice struct pointer:

package main

import (
	"fmt"
	"os"

	"github.com/jaypipes/ghw"
)

func main() {
	pci, err := ghw.PCI()
	if err != nil {
		fmt.Printf("Error getting PCI info: %v", err)
	}

	addr := "0000:00:00.0"
	if len(os.Args) == 2 {
		addr = os.Args[1]
	}
	fmt.Printf("PCI device information for %s\n", addr)
	fmt.Println("====================================================")
	deviceInfo := pci.GetDevice(addr)
	if deviceInfo == nil {
		fmt.Printf("could not retrieve PCI device information for %s\n", addr)
		return
	}

	vendor := deviceInfo.Vendor
	fmt.Printf("Vendor: %s [%s]\n", vendor.Name, vendor.ID)
	product := deviceInfo.Product
	fmt.Printf("Product: %s [%s]\n", product.Name, product.ID)
	subsystem := deviceInfo.Subsystem
	subvendor := pci.Vendors[subsystem.VendorID]
	subvendorName := "UNKNOWN"
	if subvendor != nil {
		subvendorName = subvendor.Name
	}
	fmt.Printf("Subsystem: %s [%s] (Subvendor: %s)\n", subsystem.Name, subsystem.ID, subvendorName)
	class := deviceInfo.Class
	fmt.Printf("Class: %s [%s]\n", class.Name, class.ID)
	subclass := deviceInfo.Subclass
	fmt.Printf("Subclass: %s [%s]\n", subclass.Name, subclass.ID)
	progIface := deviceInfo.ProgrammingInterface
	fmt.Printf("Programming Interface: %s [%s]\n", progIface.Name, progIface.ID)
}

Here's a sample output from my local workstation:

PCI device information for 0000:03:00.0
====================================================
Vendor: NVIDIA Corporation [10de]
Product: GP107 [GeForce GTX 1050 Ti] [1c82]
Subsystem: UNKNOWN [8613] (Subvendor: ASUSTeK Computer Inc.)
Class: Display controller [03]
Subclass: VGA compatible controller [00]
Programming Interface: VGA controller [00]
GPU

Information about the host computer's graphics hardware is returned from the ghw.GPU() function. This function returns a pointer to a ghw.GPUInfo struct.

The ghw.GPUInfo struct contains one field:

  • ghw.GPUInfo.GraphicCards is an array of pointers to ghw.GraphicsCard structs, one for each graphics card found for the systen

Each ghw.GraphicsCard struct contains the following fields:

  • ghw.GraphicsCard.Index is the system's numeric zero-based index for the card on the bus
  • ghw.GraphicsCard.Address is the PCI address for the graphics card
  • ghw.GraphicsCard.DeviceInfo is a pointer to a ghw.PCIDevice struct describing the graphics card. This may be nil if no PCI device information could be determined for the card.
  • ghw.GraphicsCard.Node is an pointer to a ghw.TopologyNode struct that the GPU/graphics card is affined to. On non-NUMA systems, this will always be nil.
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	gpu, err := ghw.GPU()
	if err != nil {
		fmt.Printf("Error getting GPU info: %v", err)
	}

	fmt.Printf("%v\n", gpu)

	for _, card := range gpu.GraphicsCards {
		fmt.Printf(" %v\n", card)
	}
}

Example output from my personal workstation:

gpu (1 graphics card)
 card #0 @0000:03:00.0 -> class: 'Display controller' vendor: 'NVIDIA Corporation' product: 'GP107 [GeForce GTX 1050 Ti]'

NOTE: You can read more about the fields of the ghw.PCIDevice struct if you'd like to dig deeper into PCI subsystem and programming interface information

NOTE: You can read more about the fields of the ghw.TopologyNode struct if you'd like to dig deeper into the NUMA/topology subsystem

Chassis

The host's chassis information is accessible with the ghw.Chassis() function. This function returns a pointer to a ghw.ChassisInfo struct.

The ghw.ChassisInfo struct contains multiple fields:

  • ghw.ChassisInfo.AssetTag is a string with the chassis asset tag
  • ghw.ChassisInfo.SerialNumber is a string with the chassis serial number
  • ghw.ChassisInfo.Type is a string with the chassis type code
  • ghw.ChassisInfo.TypeDescription is a string with a description of the chassis type
  • ghw.ChassisInfo.Vendor is a string with the chassis vendor
  • ghw.ChassisInfo.Version is a string with the chassis version

NOTE: These fields are often missing for non-server hardware. Don't be surprised to see empty string or "None" values.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	chassis, err := ghw.Chassis()
	if err != nil {
		fmt.Printf("Error getting chassis info: %v", err)
	}

	fmt.Printf("%v\n", chassis)
}

Example output from my personal workstation:

chassis type=Desktop vendor=System76 version=thelio-r1

NOTE: Some of the values such as serial numbers are shown as unknown because the Linux kernel by default disallows access to those fields if you're not running as root. They will be populated if it runs as root or otherwise you may see warnings like the following:

WARNING: Unable to read chassis_serial: open /sys/class/dmi/id/chassis_serial: permission denied

You can ignore them or use the Disabling warning messages feature to quiet things down.

BIOS

The host's basis input/output system (BIOS) information is accessible with the ghw.BIOS() function. This function returns a pointer to a ghw.BIOSInfo struct.

The ghw.BIOSInfo struct contains multiple fields:

  • ghw.BIOSInfo.Vendor is a string with the BIOS vendor
  • ghw.BIOSInfo.Version is a string with the BIOS version
  • ghw.BIOSInfo.Date is a string with the date the BIOS was flashed/created
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	bios, err := ghw.BIOS()
	if err != nil {
		fmt.Printf("Error getting BIOS info: %v", err)
	}

	fmt.Printf("%v\n", bios)
}

Example output from my personal workstation:

bios vendor=System76 version=F2 Z5 date=11/14/2018
Baseboard

The host's baseboard information is accessible with the ghw.Baseboard() function. This function returns a pointer to a ghw.BaseboardInfo struct.

The ghw.BaseboardInfo struct contains multiple fields:

  • ghw.BaseboardInfo.AssetTag is a string with the baseboard asset tag
  • ghw.BaseboardInfo.SerialNumber is a string with the baseboard serial number
  • ghw.BaseboardInfo.Vendor is a string with the baseboard vendor
  • ghw.BaseboardInfo.Version is a string with the baseboard version

NOTE: These fields are often missing for non-server hardware. Don't be surprised to see empty string or "None" values.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	baseboard, err := ghw.Baseboard()
	if err != nil {
		fmt.Printf("Error getting baseboard info: %v", err)
	}

	fmt.Printf("%v\n", baseboard)
}

Example output from my personal workstation:

baseboard vendor=System76 version=thelio-r1

NOTE: Some of the values such as serial numbers are shown as unknown because the Linux kernel by default disallows access to those fields if you're not running as root. They will be populated if it runs as root or otherwise you may see warnings like the following:

WARNING: Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied

You can ignore them or use the Disabling warning messages feature to quiet things down.

Product

The host's product information is accessible with the ghw.Product() function. This function returns a pointer to a ghw.ProductInfo struct.

The ghw.ProductInfo struct contains multiple fields:

  • ghw.ProductInfo.Family is a string describing the product family
  • ghw.ProductInfo.Name is a string with the product name
  • ghw.ProductInfo.SerialNumber is a string with the product serial number
  • ghw.ProductInfo.UUID is a string with the product UUID
  • ghw.ProductInfo.SKU is a string with the product stock unit identifier (SKU)
  • ghw.ProductInfo.Vendor is a string with the product vendor
  • ghw.ProductInfo.Version is a string with the product version

NOTE: These fields are often missing for non-server hardware. Don't be surprised to see empty string, "Default string" or "None" values.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	product, err := ghw.Product()
	if err != nil {
		fmt.Printf("Error getting product info: %v", err)
	}

	fmt.Printf("%v\n", product)
}

Example output from my personal workstation:

product family=Default string name=Thelio vendor=System76 sku=Default string version=thelio-r1

NOTE: Some of the values such as serial numbers are shown as unknown because the Linux kernel by default disallows access to those fields if you're not running as root. They will be populated if it runs as root or otherwise you may see warnings like the following:

WARNING: Unable to read product_serial: open /sys/class/dmi/id/product_serial: permission denied

You can ignore them or use the Disabling warning messages feature to quiet things down.

Serialization

All of the ghw XXXInfo structs -- e.g. ghw.CPUInfo -- have two methods for producing a serialized JSON or YAML string representation of the contained information:

  • JSONString() returns a string containing the information serialized into JSON. It accepts a single boolean parameter indicating whether to use indentation when outputting the string
  • YAMLString() returns a string containing the information serialized into YAML
package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	mem, err := ghw.Memory()
	if err != nil {
		fmt.Printf("Error getting memory info: %v", err)
	}

	fmt.Printf("%s", mem.YAMLString())
}

the above example code prints the following out on my local workstation:

memory:
  supported_page_sizes:
  - 1073741824
  - 2097152
  total_physical_bytes: 25263415296
  total_usable_bytes: 25263415296

Developers

Contributions to ghw are welcomed! Fork the repo on GitHub and submit a pull request with your proposed changes. Or, feel free to log an issue for a feature request or bug report.

Running tests

You can run unit tests easily using the make test command, like so:

[jaypipes@uberbox ghw]$ make test
go test github.com/jaypipes/ghw github.com/jaypipes/ghw/cmd/ghwc
ok      github.com/jaypipes/ghw 0.084s
?       github.com/jaypipes/ghw/cmd/ghwc    [no test files]

Documentation

Overview

package ghw can determine various hardware-related information about the host computer:

* Memory * CPU * Block storage * Topology * Network * PCI * GPU

Memory

Information about the host computer's memory can be retrieved using the Memory function which returns a pointer to a MemoryInfo struct.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	memory, err := ghw.Memory()
	if err != nil {
		fmt.Printf("Error getting memory info: %v", err)
	}

	fmt.Println(memory.String())
}

CPU

The CPU function returns a CPUInfo struct that contains information about the CPUs on the host system.

package main

import (
	"fmt"
	"math"
	"strings"

	"github.com/jaypipes/ghw"
)

func main() {
	cpu, err := ghw.CPU()
	if err != nil {
		fmt.Printf("Error getting CPU info: %v", err)
	}

	fmt.Printf("%v\n", cpu)

	for _, proc := range cpu.Processors {
		fmt.Printf(" %v\n", proc)
		for _, core := range proc.Cores {
			fmt.Printf("  %v\n", core)
		}
		if len(proc.Capabilities) > 0 {
			// pretty-print the (large) block of capability strings into rows
			// of 6 capability strings
			rows := int(math.Ceil(float64(len(proc.Capabilities)) / float64(6)))
			for row := 1; row < rows; row = row + 1 {
				rowStart := (row * 6) - 1
				rowEnd := int(math.Min(float64(rowStart+6), float64(len(proc.Capabilities))))
				rowElems := proc.Capabilities[rowStart:rowEnd]
				capStr := strings.Join(rowElems, " ")
				if row == 1 {
					fmt.Printf("  capabilities: [%s\n", capStr)
				} else if rowEnd < len(proc.Capabilities) {
					fmt.Printf("                 %s\n", capStr)
				} else {
					fmt.Printf("                 %s]\n", capStr)
				}
			}
		}
	}
}

Block storage

Information about the host computer's local block storage is returned from the Block function. This function returns a pointer to a BlockInfo struct.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	block, err := ghw.Block()
	if err != nil {
		fmt.Printf("Error getting block storage info: %v", err)
	}

	fmt.Printf("%v\n", block)

	for _, disk := range block.Disks {
		fmt.Printf(" %v\n", disk)
		for _, part := range disk.Partitions {
			fmt.Printf("  %v\n", part)
		}
	}
}

Topology

Information about the host computer's architecture (NUMA vs. SMP), the host's node layout and processor caches can be retrieved from the Topology function. This function returns a pointer to a TopologyInfo struct.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	topology, err := ghw.Topology()
	if err != nil {
		fmt.Printf("Error getting topology info: %v", err)
	}

	fmt.Printf("%v\n", topology)

	for _, node := range topology.Nodes {
		fmt.Printf(" %v\n", node)
		for _, cache := range node.Caches {
			fmt.Printf("  %v\n", cache)
		}
	}
}

Network

Information about the host computer's networking hardware is returned from the Network function. This function returns a pointer to a NetworkInfo struct.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	net, err := ghw.Network()
	if err != nil {
		fmt.Printf("Error getting network info: %v", err)
	}

	fmt.Printf("%v\n", net)

	for _, nic := range net.NICs {
		fmt.Printf(" %v\n", nic)

		enabledCaps := make([]int, 0)
		for x, cap := range nic.Capabilities {
			if cap.IsEnabled {
				enabledCaps = append(enabledCaps, x)
			}
		}
		if len(enabledCaps) > 0 {
			fmt.Printf("  enabled capabilities:\n")
			for _, x := range enabledCaps {
				fmt.Printf("   - %s\n", nic.Capabilities[x].Name)
			}
		}
	}
}

PCI

ghw contains a PCI database inspection and querying facility that allows developers to not only gather information about devices on a local PCI bus but also query for information about hardware device classes, vendor and product information.

**NOTE**: Parsing of the PCI-IDS file database is provided by the separate http://github.com/jaypipes/pcidb library. You can read that library's README for more information about the various structs that are exposed on the PCIInfo struct.

PCIInfo.ListDevices is used to iterate over a host's PCI devices:

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	pci, err := ghw.PCI()
	if err != nil {
		fmt.Printf("Error getting PCI info: %v", err)
	}
	fmt.Printf("host PCI devices:\n")
	fmt.Println("====================================================")
	devices := pci.ListDevices()
	if len(devices) == 0 {
		fmt.Printf("error: could not retrieve PCI devices\n")
		return
	}

	for _, device := range devices {
		vendor := device.Vendor
		vendorName := vendor.Name
		if len(vendor.Name) > 20 {
			vendorName = string([]byte(vendorName)[0:17]) + "..."
		}
		product := device.Product
		productName := product.Name
		if len(product.Name) > 40 {
			productName = string([]byte(productName)[0:37]) + "..."
		}
		fmt.Printf("%-12s\t%-20s\t%-40s\n", device.Address, vendorName, productName)
	}
}

The following code snippet shows how to call the PCIInfo.GetDevice method and use its returned PCIDevice struct pointer:

package main

import (
	"fmt"
	"os"

	"github.com/jaypipes/ghw"
)

func main() {
	pci, err := ghw.PCI()
	if err != nil {
		fmt.Printf("Error getting PCI info: %v", err)
	}

	addr := "0000:00:00.0"
	if len(os.Args) == 2 {
		addr = os.Args[1]
	}
	fmt.Printf("PCI device information for %s\n", addr)
	fmt.Println("====================================================")
	deviceInfo := pci.GetDevice(addr)
	if deviceInfo == nil {
		fmt.Printf("could not retrieve PCI device information for %s\n", addr)
		return
	}

	vendor := deviceInfo.Vendor
	fmt.Printf("Vendor: %s [%s]\n", vendor.Name, vendor.ID)
	product := deviceInfo.Product
	fmt.Printf("Product: %s [%s]\n", product.Name, product.ID)
	subsystem := deviceInfo.Subsystem
	subvendor := pci.Vendors[subsystem.VendorID]
	subvendorName := "UNKNOWN"
	if subvendor != nil {
		subvendorName = subvendor.Name
	}
	fmt.Printf("Subsystem: %s [%s] (Subvendor: %s)\n", subsystem.Name, subsystem.ID, subvendorName)
	class := deviceInfo.Class
	fmt.Printf("Class: %s [%s]\n", class.Name, class.ID)
	subclass := deviceInfo.Subclass
	fmt.Printf("Subclass: %s [%s]\n", subclass.Name, subclass.ID)
	progIface := deviceInfo.ProgrammingInterface
	fmt.Printf("Programming Interface: %s [%s]\n", progIface.Name, progIface.ID)
}

GPU

Information about the host computer's graphics hardware is returned from the GPU function. This function returns a pointer to a GPUInfo struct.

package main

import (
	"fmt"

	"github.com/jaypipes/ghw"
)

func main() {
	gpu, err := ghw.GPU()
	if err != nil {
		fmt.Printf("Error getting GPU info: %v", err)
	}

	fmt.Printf("%v\n", gpu)

	for _, card := range gpu.GraphicsCards {
		fmt.Printf(" %v\n", card)
	}
}

Index

Constants

View Source
const (
	UNKNOWN = "unknown"
)

Variables

View Source
var (
	KB int64 = 1024
	MB       = KB * 1024
	GB       = MB * 1024
	TB       = GB * 1024
	PB       = TB * 1024
	EB       = PB * 1024
)

Functions

func DiskBusPath

func DiskBusPath(disk string) string

DiskBusPath has been deprecated in 0.2. Please use the Disk.BusPath attribute. TODO(jaypipes): Remove in 1.0.

func DiskModel

func DiskModel(disk string) string

DiskModel has been deprecated in 0.2. Please use the Disk.Model attribute. TODO(jaypipes): Remove in 1.0.

func DiskNUMANodeID

func DiskNUMANodeID(disk string) int

DiskNUMANodeID has been deprecated in 0.2. Please use the Disk.NUMANodeID attribute. TODO(jaypipes): Remove in 1.0.

func DiskPhysicalBlockSizeBytes

func DiskPhysicalBlockSizeBytes(disk string) uint64

DiskPhysicalBlockSizeBytes has been deprecated in 0.2. Please use the Disk.PhysicalBlockSizeBytes attribute. TODO(jaypipes): Remove in 1.0.

func DiskSerialNumber

func DiskSerialNumber(disk string) string

DiskSerialNumber has been deprecated in 0.2. Please use the Disk.SerialNumber attribute. TODO(jaypipes): Remove in 1.0.

func DiskSizeBytes

func DiskSizeBytes(disk string) uint64

DiskSizeBytes has been deprecated in 0.2. Please use the Disk.SizeBytes attribute. TODO(jaypipes): Remove in 1.0.

func DiskVendor

func DiskVendor(disk string) string

DiskVendor has been deprecated in 0.2. Please use the Disk.Vendor attribute. TODO(jaypipes): Remove in 1.0.

func DiskWWN

func DiskWWN(disk string) string

DiskWWN has been deprecated in 0.2. Please use the Disk.WWN attribute. TODO(jaypipes): Remove in 1.0.

func PartitionInfo

func PartitionInfo(part string) (string, string, bool)

PartitionInfo has been deprecated in 0.2. Please use the Partition struct. TODO(jaypipes): Remove in 1.0.

func PartitionIsReadOnly

func PartitionIsReadOnly(part string) bool

PartitionIsReadOnly has been deprecated in 0.2. Please use the Partition.IsReadOnly attribute. TODO(jaypipes): Remove in 1.0.

func PartitionMountPoint

func PartitionMountPoint(part string) string

PartitionMountPoint has been deprecated in 0.2. Please use the Partition.MountPoint attribute. TODO(jaypipes): Remove in 1.0.

func PartitionSizeBytes

func PartitionSizeBytes(part string) uint64

PartitionSizeBytes has been deprecated in 0.2. Please use the Partition.SizeBytes attribute. TODO(jaypipes): Remove in 1.0.

func PartitionType

func PartitionType(part string) string

PartitionType has been deprecated in 0.2. Please use the Partition.Type attribute. TODO(jaypipes): Remove in 1.0.

Types

type Architecture

type Architecture int

Architecture describes the overall hardware architecture. It can be either Symmetric Multi-Processor (SMP) or Non-Uniform Memory Access (NUMA)

const (
	// SMP is a Symmetric Multi-Processor system
	ARCHITECTURE_SMP Architecture = iota
	// NUMA is a Non-Uniform Memory Access system
	ARCHITECTURE_NUMA
)

func (Architecture) MarshalJSON

func (a Architecture) MarshalJSON() ([]byte, error)

NOTE(jaypipes): since serialized output is as "official" as we're going to get, let's lowercase the string output when serializing, in order to "normalize" the expected serialized output

func (Architecture) String

func (a Architecture) String() string

type BIOSInfo

type BIOSInfo struct {
	Vendor  string `json:"vendor"`
	Version string `json:"version"`
	Date    string `json:"date"`
}

BIOSInfo defines BIOS release information

func BIOS

func BIOS(opts ...*WithOption) (*BIOSInfo, error)

BIOS returns a pointer to a BIOSInfo struct containing information about the host's BIOS

func (*BIOSInfo) JSONString

func (info *BIOSInfo) JSONString(indent bool) string

JSONString returns a string with the BIOS information formatted as JSON under a top-level "bios:" key

func (*BIOSInfo) String

func (i *BIOSInfo) String() string

func (*BIOSInfo) YAMLString

func (info *BIOSInfo) YAMLString() string

YAMLString returns a string with the BIOS information formatted as YAML under a top-level "dmi:" key

type BaseboardInfo

type BaseboardInfo struct {
	AssetTag     string `json:"asset_tag"`
	SerialNumber string `json:"serial_number"`
	Vendor       string `json:"vendor"`
	Version      string `json:"version"`
}

BaseboardInfo defines baseboard release information

func Baseboard

func Baseboard(opts ...*WithOption) (*BaseboardInfo, error)

Baseboard returns a pointer to a BaseboardInfo struct containing information about the host's baseboard

func (*BaseboardInfo) JSONString

func (info *BaseboardInfo) JSONString(indent bool) string

JSONString returns a string with the baseboard information formatted as JSON under a top-level "baseboard:" key

func (*BaseboardInfo) String

func (i *BaseboardInfo) String() string

func (*BaseboardInfo) YAMLString

func (info *BaseboardInfo) YAMLString() string

YAMLString returns a string with the baseboard information formatted as YAML under a top-level "dmi:" key

type BlockInfo

type BlockInfo struct {
	// TODO(jaypipes): Deprecate this field and replace with TotalSizeBytes
	TotalPhysicalBytes uint64       `json:"total_size_bytes"`
	Disks              []*Disk      `json:"disks"`
	Partitions         []*Partition `json:"-"`
}

BlockInfo describes all disk drives and partitions in the host system.

func Block

func Block(opts ...*WithOption) (*BlockInfo, error)

Block returns a BlockInfo struct that describes the block storage resources of the host system.

func (*BlockInfo) JSONString

func (i *BlockInfo) JSONString(indent bool) string

JSONString returns a string with the block information formatted as JSON under a top-level "block:" key

func (*BlockInfo) String

func (i *BlockInfo) String() string

func (*BlockInfo) YAMLString

func (i *BlockInfo) YAMLString() string

YAMLString returns a string with the block information formatted as YAML under a top-level "block:" key

type BusType

type BusType int
const (
	BUS_TYPE_UNKNOWN BusType = iota
	BUS_TYPE_IDE
	BUS_TYPE_PCI
	BUS_TYPE_SCSI
	BUS_TYPE_NVME
	BUS_TYPE_VIRTIO
)

func (BusType) MarshalJSON

func (bt BusType) MarshalJSON() ([]byte, error)

NOTE(jaypipes): since serialized output is as "official" as we're going to get, let's lowercase the string output when serializing, in order to "normalize" the expected serialized output

func (BusType) String

func (bt BusType) String() string

type CPUInfo

type CPUInfo struct {
	// TotalCores is the total number of physical cores the host system
	// contains
	TotalCores uint32 `json:"total_cores"`
	// TotalThreads is the total number of hardware threads the host system
	// contains
	TotalThreads uint32 `json:"total_threads"`
	// Processors is a slice of Processor struct pointers, one for each
	// physical processor package contained in the host
	Processors []*Processor `json:"processors"`
}

CPUInfo describes all central processing unit (CPU) functionality on a host. Returned by the `ghw.CPU()` function.

func CPU

func CPU(opts ...*WithOption) (*CPUInfo, error)

CPU returns a CPUInfo struct that contains information about the CPUs on the host system

func (*CPUInfo) JSONString

func (i *CPUInfo) JSONString(indent bool) string

JSONString returns a string with the cpu information formatted as JSON under a top-level "cpu:" key

func (*CPUInfo) String

func (i *CPUInfo) String() string

String returns a short string indicating a summary of CPU information

func (*CPUInfo) YAMLString

func (i *CPUInfo) YAMLString() string

YAMLString returns a string with the cpu information formatted as YAML under a top-level "cpu:" key

type ChassisInfo

type ChassisInfo struct {
	AssetTag        string `json:"asset_tag"`
	SerialNumber    string `json:"serial_number"`
	Type            string `json:"type"`
	TypeDescription string `json:"type_description"`
	Vendor          string `json:"vendor"`
	Version         string `json:"version"`
}

ChassisInfo defines chassis release information

func Chassis

func Chassis(opts ...*WithOption) (*ChassisInfo, error)

Chassis returns a pointer to a ChassisInfo struct containing information about the host's chassis

func (*ChassisInfo) JSONString

func (info *ChassisInfo) JSONString(indent bool) string

JSONString returns a string with the chassis information formatted as JSON under a top-level "chassis:" key

func (*ChassisInfo) String

func (i *ChassisInfo) String() string

func (*ChassisInfo) YAMLString

func (info *ChassisInfo) YAMLString() string

YAMLString returns a string with the chassis information formatted as YAML under a top-level "dmi:" key

type Disk

type Disk struct {
	Name                   string            `json:"name"`
	SizeBytes              uint64            `json:"size_bytes"`
	PhysicalBlockSizeBytes uint64            `json:"physical_block_size_bytes"`
	DriveType              DriveType         `json:"drive_type"`
	IsRemovable            bool              `json:"removable"`
	StorageController      StorageController `json:"storage_controller"`
	// NOTE(jaypipes): BusType is DEPRECATED. Use the DriveType and
	// StorageController fields instead
	BusType BusType `json:"-"`
	BusPath string  `json:"bus_path"`
	// TODO(jaypipes): Convert this to a TopologyNode struct pointer and then
	// add to serialized output as "numa_node,omitempty"
	NUMANodeID   int          `json:"-"`
	Vendor       string       `json:"vendor"`
	Model        string       `json:"model"`
	SerialNumber string       `json:"serial_number"`
	WWN          string       `json:"wwn"`
	Partitions   []*Partition `json:"partitions"`
}

Disk describes a single disk drive on the host system. Disk drives provide raw block storage resources.

func Disks

func Disks() []*Disk

Disks has been deprecated in 0.2. Please use the BlockInfo.Disks attribute. TODO(jaypipes): Remove in 1.0.

func (*Disk) String

func (d *Disk) String() string

type DriveType

type DriveType int

DriveType describes the general category of drive device

const (
	DRIVE_TYPE_UNKNOWN DriveType = iota
	DRIVE_TYPE_HDD               // Hard disk drive
	DRIVE_TYPE_FDD               // Floppy disk drive
	DRIVE_TYPE_ODD               // Optical disk drive
	DRIVE_TYPE_SSD               // Solid-state drive
)

func (DriveType) MarshalJSON

func (dt DriveType) MarshalJSON() ([]byte, error)

NOTE(jaypipes): since serialized output is as "official" as we're going to get, let's lowercase the string output when serializing, in order to "normalize" the expected serialized output

func (DriveType) String

func (dt DriveType) String() string

type GPUInfo

type GPUInfo struct {
	GraphicsCards []*GraphicsCard `json:"cards"`
}

func GPU

func GPU(opts ...*WithOption) (*GPUInfo, error)

func (*GPUInfo) JSONString

func (i *GPUInfo) JSONString(indent bool) string

JSONString returns a string with the gpu information formatted as JSON under a top-level "gpu:" key

func (*GPUInfo) String

func (i *GPUInfo) String() string

func (*GPUInfo) YAMLString

func (i *GPUInfo) YAMLString() string

YAMLString returns a string with the gpu information formatted as YAML under a top-level "gpu:" key

type GraphicsCard

type GraphicsCard struct {
	// the PCI address where the graphics card can be found
	Address string `json:"address"`
	// The "index" of the card on the bus (generally not useful information,
	// but might as well include it)
	Index int `json:"index"`
	// pointer to a PCIDevice struct that describes the vendor and product
	// model, etc
	// TODO(jaypipes): Rename this field to PCI, instead of DeviceInfo
	DeviceInfo *PCIDevice `json:"pci"`
	// Topology node that the graphics card is affined to. Will be nil if the
	// architecture is not NUMA.
	Node *TopologyNode `json:"node,omitempty"`
}

func (*GraphicsCard) String

func (card *GraphicsCard) String() string

type HostInfo

type HostInfo struct {
	Memory    *MemoryInfo    `json:"memory"`
	Block     *BlockInfo     `json:"block"`
	CPU       *CPUInfo       `json:"cpu"`
	Topology  *TopologyInfo  `json:"topology"`
	Network   *NetworkInfo   `json:"network"`
	GPU       *GPUInfo       `json:"gpu"`
	Chassis   *ChassisInfo   `json:"chassis"`
	BIOS      *BIOSInfo      `json:"bios"`
	Baseboard *BaseboardInfo `json:"baseboard"`
	Product   *ProductInfo   `json:"product"`
}

HostInfo is a wrapper struct containing information about the host system's memory, block storage, CPU, etc

func Host

func Host(opts ...*WithOption) (*HostInfo, error)

Host returns a pointer to a HostInfo struct that contains fields with information about the host system's CPU, memory, network devices, etc

func (*HostInfo) JSONString

func (i *HostInfo) JSONString(indent bool) string

JSONString returns a string with the host information formatted as JSON under a top-level "host:" key

func (*HostInfo) String

func (info *HostInfo) String() string

String returns a newline-separated output of the HostInfo's component structs' String-ified output

func (*HostInfo) YAMLString

func (i *HostInfo) YAMLString() string

YAMLString returns a string with the host information formatted as YAML under a top-level "host:" key

type MemoryCache

type MemoryCache struct {
	Level     uint8           `json:"level"`
	Type      MemoryCacheType `json:"type"`
	SizeBytes uint64          `json:"size_bytes"`
	// The set of logical processors (hardware threads) that have access to the
	// cache
	LogicalProcessors []uint32 `json:"logical_processors"`
}

func (*MemoryCache) String

func (c *MemoryCache) String() string

type MemoryCacheType

type MemoryCacheType int
const (
	MEMORY_CACHE_TYPE_UNIFIED MemoryCacheType = iota
	MEMORY_CACHE_TYPE_INSTRUCTION
	MEMORY_CACHE_TYPE_DATA
)

func (MemoryCacheType) MarshalJSON

func (a MemoryCacheType) MarshalJSON() ([]byte, error)

NOTE(jaypipes): since serialized output is as "official" as we're going to get, let's lowercase the string output when serializing, in order to "normalize" the expected serialized output

func (MemoryCacheType) String

func (a MemoryCacheType) String() string

type MemoryInfo

type MemoryInfo struct {
	TotalPhysicalBytes int64 `json:"total_physical_bytes"`
	TotalUsableBytes   int64 `json:"total_usable_bytes"`
	// An array of sizes, in bytes, of memory pages supported by the host
	SupportedPageSizes []uint64 `json:"supported_page_sizes"`
}

func Memory

func Memory(opts ...*WithOption) (*MemoryInfo, error)

func (*MemoryInfo) JSONString

func (i *MemoryInfo) JSONString(indent bool) string

JSONString returns a string with the memory information formatted as JSON under a top-level "memory:" key

func (*MemoryInfo) String

func (i *MemoryInfo) String() string

func (*MemoryInfo) YAMLString

func (i *MemoryInfo) YAMLString() string

YAMLString returns a string with the memory information formatted as YAML under a top-level "memory:" key

type NIC

type NIC struct {
	Name         string           `json:"name"`
	MacAddress   string           `json:"mac_address"`
	IsVirtual    bool             `json:"is_virtual"`
	Capabilities []*NICCapability `json:"capabilities"`
}

func NICs

func NICs() []*NIC

NICS has been deprecated in 0.2. Please use the NetworkInfo.NICs attribute. TODO(jaypipes): Remove in 1.0.

func (*NIC) String

func (n *NIC) String() string

type NICCapability

type NICCapability struct {
	Name      string `json:"name"`
	IsEnabled bool   `json:"is_enabled"`
	CanEnable bool   `json:"can_enable"`
}

type NetworkInfo

type NetworkInfo struct {
	NICs []*NIC `json:"nics"`
}

func Network

func Network(opts ...*WithOption) (*NetworkInfo, error)

func (*NetworkInfo) JSONString

func (i *NetworkInfo) JSONString(indent bool) string

JSONString returns a string with the net information formatted as JSON under a top-level "net:" key

func (*NetworkInfo) String

func (i *NetworkInfo) String() string

func (*NetworkInfo) YAMLString

func (i *NetworkInfo) YAMLString() string

YAMLString returns a string with the net information formatted as YAML under a top-level "net:" key

type PCIAddress

type PCIAddress struct {
	Domain   string
	Bus      string
	Slot     string
	Function string
}

func PCIAddressFromString

func PCIAddressFromString(address string) *PCIAddress

Given a string address, returns a complete PCIAddress struct, filled in with domain, bus, slot and function components. The address string may either be in $BUS:$SLOT.$FUNCTION (BSF) format or it can be a full PCI address that includes the 4-digit $DOMAIN information as well: $DOMAIN:$BUS:$SLOT.$FUNCTION.

Returns "" if the address string wasn't a valid PCI address.

type PCIDevice

type PCIDevice struct {
	// The PCI address of the device
	Address   string         `json:"address"`
	Vendor    *pcidb.Vendor  `json:"vendor"`
	Product   *pcidb.Product `json:"product"`
	Subsystem *pcidb.Product `json:"subsystem"`
	// optional subvendor/sub-device information
	Class *pcidb.Class `json:"class"`
	// optional sub-class for the device
	Subclass *pcidb.Subclass `json:"subclass"`
	// optional programming interface
	ProgrammingInterface *pcidb.ProgrammingInterface `json:"programming_interface"`
}

func (*PCIDevice) MarshalJSON

func (pd *PCIDevice) MarshalJSON() ([]byte, error)

NOTE(jaypipes) PCIDevice has a custom JSON marshaller because we don't want to serialize the entire PCIDB information for the Vendor (which includes all of the vendor's products, etc). Instead, we simply serialize the ID and human-readable name of the vendor, product, class, etc.

func (*PCIDevice) String

func (di *PCIDevice) String() string

type PCIInfo

type PCIInfo struct {

	// hash of class ID -> class information
	Classes map[string]*pcidb.Class
	// hash of vendor ID -> vendor information
	Vendors map[string]*pcidb.Vendor
	// hash of vendor ID + product/device ID -> product information
	Products map[string]*pcidb.Product
	// contains filtered or unexported fields
}

func PCI

func PCI(opts ...*WithOption) (*PCIInfo, error)

func (*PCIInfo) GetDevice

func (info *PCIInfo) GetDevice(address string) *PCIDevice

GetDevice returns a pointer to a PCIDevice struct that describes the PCI device at the requested address. If no such device could be found, returns nil

func (*PCIInfo) ListDevices

func (info *PCIInfo) ListDevices() []*PCIDevice

ListDevices returns a list of pointers to PCIDevice structs present on the host system

type Partition

type Partition struct {
	Disk       *Disk  `json:"-"`
	Name       string `json:"name"`
	Label      string `json:"label"`
	MountPoint string `json:"mount_point"`
	SizeBytes  uint64 `json:"size_bytes"`
	Type       string `json:"type"`
	IsReadOnly bool   `json:"read_only"`
}

Partition describes a logical division of a Disk.

func DiskPartitions

func DiskPartitions(disk string) []*Partition

DiskPartitions has been deprecated in 0.2. Please use the Disk.Partitions attribute. TODO(jaypipes): Remove in 1.0.

func (*Partition) String

func (p *Partition) String() string

type Processor

type Processor struct {
	// TODO(jaypipes): Deprecated in 0.2, remove in 1.0
	Id int `json:"-"`
	// ID is the physical processor `uint32` ID according to the system
	ID int `json:"id"`
	// NumCores is the number of physical cores in the processor package
	NumCores uint32 `json:"total_cores"`
	// NumThreads is the number of hardware threads in the processor package
	NumThreads uint32 `json:"total_threads"`
	// Vendor is a string containing the vendor name
	Vendor string `json:"vendor"`
	// Model` is a string containing the vendor's model name
	Model string `json:"model"`
	// Capabilities is a slice of strings indicating the features the processor
	// has enabled
	Capabilities []string `json:"capabilities"`
	// Cores is a slice of ProcessorCore` struct pointers that are packed onto
	// this physical processor
	Cores []*ProcessorCore `json:"cores"`
	//speed/cache
	Speed string `json:"speed"`
	Cache string `json:"cache"`
}

Processor describes a physical host central processing unit (CPU).

func Processors

func Processors() []*Processor

Processors has been DEPRECATED in 0.2 and will be REMOVED in 1.0. Please use the CPUInfo.Processors attribute. TODO(jaypipes): Remove in 1.0

func (*Processor) HasCapability

func (p *Processor) HasCapability(find string) bool

HasCapability returns true if the Processor has the supplied cpuid capability, false otherwise. Example of cpuid capabilities would be 'vmx' or 'sse4_2'. To see a list of potential cpuid capabilitiies, see the section on CPUID feature bits in the following article:

https://en.wikipedia.org/wiki/CPUID

func (*Processor) String

func (p *Processor) String() string

String returns a short string describing the Processor

type ProcessorCore

type ProcessorCore struct {
	// TODO(jaypipes): Deprecated in 0.2, remove in 1.0
	Id int `json:"-"`
	// ID is the `uint32` identifier that the host gave this core. Note that
	// this does *not* necessarily equate to a zero-based index of the core
	// within a physical package. For example, the core IDs for an Intel Core
	// i7 are 0, 1, 2, 8, 9, and 10
	ID int `json:"id"`
	// Index is the zero-based index of the core on the physical processor
	// package
	Index int `json:"index"`
	// NumThreads is the number of hardware threads associated with the core
	NumThreads uint32 `json:"total_threads"`
	// LogicalProcessors is a slice of ints representing the logical processor
	// IDs assigned to any processing unit for the core
	LogicalProcessors []int `json:"logical_processors"`
}

ProcessorCore describes a physical host processor core. A processor core is a separate processing unit within some types of central processing units (CPU).

func (*ProcessorCore) String

func (c *ProcessorCore) String() string

String returns a short string indicating important information about the processor core

type ProductInfo

type ProductInfo struct {
	Family       string `json:"family"`
	Name         string `json:"name"`
	Vendor       string `json:"vendor"`
	SerialNumber string `json:"serial_number"`
	UUID         string `json:"uuid"`
	SKU          string `json:"sku"`
	Version      string `json:"version"`
}

ProductInfo defines product information

func Product

func Product(opts ...*WithOption) (*ProductInfo, error)

Product returns a pointer to a ProductInfo struct containing information about the host's product

func (*ProductInfo) JSONString

func (info *ProductInfo) JSONString(indent bool) string

JSONString returns a string with the product information formatted as JSON under a top-level "product:" key

func (*ProductInfo) String

func (i *ProductInfo) String() string

func (*ProductInfo) YAMLString

func (info *ProductInfo) YAMLString() string

YAMLString returns a string with the product information formatted as YAML under a top-level "dmi:" key

type SortByLogicalProcessorId

type SortByLogicalProcessorId []uint32

func (SortByLogicalProcessorId) Len

func (a SortByLogicalProcessorId) Len() int

func (SortByLogicalProcessorId) Less

func (a SortByLogicalProcessorId) Less(i, j int) bool

func (SortByLogicalProcessorId) Swap

func (a SortByLogicalProcessorId) Swap(i, j int)

type SortByMemoryCacheLevelTypeFirstProcessor

type SortByMemoryCacheLevelTypeFirstProcessor []*MemoryCache

func (SortByMemoryCacheLevelTypeFirstProcessor) Len

func (SortByMemoryCacheLevelTypeFirstProcessor) Less

func (SortByMemoryCacheLevelTypeFirstProcessor) Swap

type StorageController

type StorageController int

StorageController is a category of block storage controller/driver. It represents more of the physical hardware interface than the storage protocol, which represents more of the software interface.

See discussion on https://github.com/jaypipes/ghw/issues/117

const (
	STORAGE_CONTROLLER_UNKNOWN StorageController = iota
	STORAGE_CONTROLLER_IDE                       // Integrated Drive Electronics
	STORAGE_CONTROLLER_SCSI                      // Small computer system interface
	STORAGE_CONTROLLER_NVME                      // Non-volatile Memory Express
	STORAGE_CONTROLLER_VIRTIO                    // Virtualized storage controller/driver
	STORAGE_CONTROLLER_MMC                       // Multi-media controller (used for mobile phone storage devices)
)

func (StorageController) MarshalJSON

func (sc StorageController) MarshalJSON() ([]byte, error)

NOTE(jaypipes): since serialized output is as "official" as we're going to get, let's lowercase the string output when serializing, in order to "normalize" the expected serialized output

func (StorageController) String

func (sc StorageController) String() string

type TopologyInfo

type TopologyInfo struct {
	Architecture Architecture    `json:"architecture"`
	Nodes        []*TopologyNode `json:"nodes"`
}

TopologyInfo describes the system topology for the host hardware

func Topology

func Topology(opts ...*WithOption) (*TopologyInfo, error)

Topology returns a TopologyInfo struct that describes the system topology of the host hardware

func (*TopologyInfo) JSONString

func (i *TopologyInfo) JSONString(indent bool) string

JSONString returns a string with the topology information formatted as JSON under a top-level "topology:" key

func (*TopologyInfo) String

func (i *TopologyInfo) String() string

func (*TopologyInfo) YAMLString

func (i *TopologyInfo) YAMLString() string

YAMLString returns a string with the topology information formatted as YAML under a top-level "topology:" key

type TopologyNode

type TopologyNode struct {
	// TODO(jaypipes): Deprecated in 0.2, remove in 1.0
	Id     int              `json:"-"`
	ID     int              `json:"id"`
	Cores  []*ProcessorCore `json:"cores"`
	Caches []*MemoryCache   `json:"caches"`
}

TopologyNode is an abstract construct representing a collection of processors and various levels of memory cache that those processors share. In a NUMA architecture, there are multiple NUMA nodes, abstracted here as multiple TopologyNode structs. In an SMP architecture, a single TopologyNode will be available in the TopologyInfo struct and this single struct can be used to describe the levels of memory caching available to the single physical processor package's physical processor cores

func TopologyNodes

func TopologyNodes() ([]*TopologyNode, error)

TopologyNodes has been deprecated in 0.2. Please use the TopologyInfo.Nodes attribute. TODO(jaypipes): Remove in 1.0.

func (*TopologyNode) String

func (n *TopologyNode) String() string

type WithOption

type WithOption struct {
	// To facilitate querying of sysfs filesystems that are bind-mounted to a
	// non-default root mountpoint, we allow users to set the GHW_CHROOT environ
	// vairable to an alternate mountpoint. For instance, assume that the user of
	// ghw is a Golang binary being executed from an application container that has
	// certain host filesystems bind-mounted into the container at /host. The user
	// would ensure the GHW_CHROOT environ variable is set to "/host" and ghw will
	// build its paths from that location instead of /
	Chroot *string
}

WithOption is used to represent optionally-configured settings. Each field is a pointer to some concrete value so that we can tell when something has been set or left unset.

func WithChroot

func WithChroot(dir string) *WithOption

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL