-
Notifications
You must be signed in to change notification settings - Fork 549
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose processor and memory information from SMBIOS as Talos resources. Output from QEMU: ```bash ❯ talosctl -n 10.5.0.2 get cpu NODE NAMESPACE TYPE ID VERSION MANUFACTURER MODEL CORES THREADS 10.5.0.2 hardware Processor CPU-0 1 QEMU pc-q35-6.2 4 1 ❯ talosctl -n 10.5.0.2 get ram NODE NAMESPACE TYPE ID VERSION MANUFACTURER MODEL SIZE 10.5.0.2 hardware Memory DIMM-0 1 QEMU 2048 ❯ talosctl -n 10.5.0.2 get cpu CPU-0 -o yaml node: 10.5.0.2 metadata: namespace: hardware type: Processors.hardware.talos.dev id: CPU-0 version: 1 owner: hardware.SystemInfoController phase: running created: 2022-05-19T13:58:12Z updated: 2022-05-19T13:58:12Z spec: socket: CPU 0 manufacturer: QEMU productName: pc-q35-6.2 maxSpeed: 2000 bootSpeed: 2000 status: 65 coreCount: 4 coreEnabled: 4 threadCount: 1 ❯ talosctl -n 10.5.0.2 get ram DIMM-0 -o yaml node: 10.5.0.2 metadata: namespace: hardware type: Memories.hardware.talos.dev id: DIMM-0 version: 1 owner: hardware.SystemInfoController phase: running created: 2022-05-19T13:58:12Z updated: 2022-05-19T13:58:12Z spec: size: 2048 deviceLocator: DIMM 0 bankLocator: "" speed: 0 manufacturer: QEMU ``` Signed-off-by: Noel Georgi <[email protected]>
- Loading branch information
Showing
17 changed files
with
705 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
// Package hardware implements adapters wrapping resources/hardware to provide additional functionality. | ||
package hardware |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware | ||
|
||
import ( | ||
"github.com/talos-systems/go-smbios/smbios" | ||
|
||
"github.com/talos-systems/talos/pkg/machinery/resources/hardware" | ||
) | ||
|
||
// Memory adapter provider conversion from smbios.SMBIOS. | ||
// | ||
//nolint:revive,golint | ||
func Memory(m *hardware.Memory) memory { | ||
return memory{ | ||
Memory: m, | ||
} | ||
} | ||
|
||
type memory struct { | ||
*hardware.Memory | ||
} | ||
|
||
// Update current processor info. | ||
func (m memory) Update(memory *smbios.MemoryDevice) { | ||
translateProcessorInfo := func(in *smbios.MemoryDevice) hardware.MemorySpec { | ||
var memorySpec hardware.MemorySpec | ||
|
||
if in.Size != 0 && in.Size != 0xFFFF { | ||
var size uint32 | ||
|
||
if in.Size == 0x7FFF { | ||
size = uint32(in.ExtendedSize) | ||
} else { | ||
size = uint32(in.Size) | ||
} | ||
|
||
memorySpec.AssetTag = in.AssetTag | ||
memorySpec.BankLocator = in.BankLocator | ||
memorySpec.DeviceLocator = in.DeviceLocator | ||
memorySpec.Manufacturer = in.Manufacturer | ||
memorySpec.ProductName = in.PartNumber | ||
memorySpec.SerialNumber = in.SerialNumber | ||
memorySpec.Size = size | ||
memorySpec.Speed = uint32(in.Speed) | ||
} | ||
|
||
return memorySpec | ||
} | ||
|
||
*m.Memory.TypedSpec() = translateProcessorInfo(memory) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware | ||
|
||
import ( | ||
"github.com/talos-systems/go-smbios/smbios" | ||
|
||
"github.com/talos-systems/talos/pkg/machinery/resources/hardware" | ||
) | ||
|
||
// Processor adapter provider conversion from smbios.SMBIOS. | ||
// | ||
//nolint:revive,golint | ||
func Processor(p *hardware.Processor) processor { | ||
return processor{ | ||
Processor: p, | ||
} | ||
} | ||
|
||
type processor struct { | ||
*hardware.Processor | ||
} | ||
|
||
// Update current processor info. | ||
func (p processor) Update(processor *smbios.ProcessorInformation) { | ||
translateProcessorInfo := func(in *smbios.ProcessorInformation) hardware.ProcessorSpec { | ||
var processorSpec hardware.ProcessorSpec | ||
|
||
if in.Status.SocketPopulated() { | ||
processorSpec.Socket = in.SocketDesignation | ||
processorSpec.Manufacturer = in.ProcessorManufacturer | ||
processorSpec.ProductName = in.ProcessorVersion | ||
processorSpec.MaxSpeed = uint32(in.MaxSpeed) | ||
processorSpec.BootSpeed = uint32(in.CurrentSpeed) | ||
processorSpec.Status = uint32(in.Status) | ||
processorSpec.SerialNumber = in.SerialNumber | ||
processorSpec.AssetTag = in.AssetTag | ||
processorSpec.PartNumber = in.PartNumber | ||
processorSpec.CoreCount = uint32(in.CoreCount) | ||
processorSpec.CoreEnabled = uint32(in.CoreEnabled) | ||
processorSpec.ThreadCount = uint32(in.ThreadCount) | ||
} | ||
|
||
return processorSpec | ||
} | ||
|
||
*p.Processor.TypedSpec() = translateProcessorInfo(processor) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware |
112 changes: 112 additions & 0 deletions
112
internal/app/machined/pkg/controllers/hardware/hardware_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware_test | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"sync" | ||
"time" | ||
|
||
"github.com/cosi-project/runtime/pkg/controller/runtime" | ||
"github.com/cosi-project/runtime/pkg/resource" | ||
"github.com/cosi-project/runtime/pkg/state" | ||
"github.com/cosi-project/runtime/pkg/state/impl/inmem" | ||
"github.com/cosi-project/runtime/pkg/state/impl/namespaced" | ||
"github.com/stretchr/testify/suite" | ||
"github.com/talos-systems/go-retry/retry" | ||
|
||
"github.com/talos-systems/talos/pkg/logging" | ||
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" | ||
"github.com/talos-systems/talos/pkg/machinery/resources/config" | ||
) | ||
|
||
type HardwareSuite struct { | ||
suite.Suite | ||
|
||
state state.State | ||
|
||
runtime *runtime.Runtime | ||
wg sync.WaitGroup | ||
|
||
ctx context.Context //nolint:containedctx | ||
ctxCancel context.CancelFunc | ||
} | ||
|
||
func (suite *HardwareSuite) SetupTest() { | ||
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute) | ||
|
||
suite.state = state.WrapCore(namespaced.NewState(inmem.Build)) | ||
|
||
var err error | ||
|
||
logger := logging.Wrap(log.Writer()) | ||
|
||
suite.runtime, err = runtime.NewRuntime(suite.state, logger) | ||
suite.Require().NoError(err) | ||
} | ||
|
||
func (suite *HardwareSuite) startRuntime() { | ||
suite.wg.Add(1) | ||
|
||
go func() { | ||
defer suite.wg.Done() | ||
|
||
suite.Assert().NoError(suite.runtime.Run(suite.ctx)) | ||
}() | ||
} | ||
|
||
func (suite *HardwareSuite) assertResource(md resource.Metadata, check func(res resource.Resource) error) func() error { | ||
return func() error { | ||
r, err := suite.state.Get(suite.ctx, md) | ||
if err != nil { | ||
if state.IsNotFoundError(err) { | ||
return retry.ExpectedError(err) | ||
} | ||
|
||
return err | ||
} | ||
|
||
return check(r) | ||
} | ||
} | ||
|
||
func (suite *HardwareSuite) assertNoResource(md resource.Metadata) func() error { | ||
return func() error { | ||
_, err := suite.state.Get(suite.ctx, md) | ||
if err == nil { | ||
return retry.ExpectedErrorf("resource %s still exists", md) | ||
} | ||
|
||
if state.IsNotFoundError(err) { | ||
return nil | ||
} | ||
|
||
return err | ||
} | ||
} | ||
|
||
func (suite *HardwareSuite) TearDownTest() { | ||
suite.T().Log("tear down") | ||
|
||
suite.ctxCancel() | ||
|
||
suite.wg.Wait() | ||
|
||
// trigger updates in resources to stop watch loops | ||
err := suite.state.Create( | ||
context.Background(), config.NewMachineConfig( | ||
&v1alpha1.Config{ | ||
ConfigVersion: "v1alpha1", | ||
MachineConfig: &v1alpha1.MachineConfig{}, | ||
}, | ||
), | ||
) | ||
if state.IsConflictError(err) { | ||
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) | ||
} | ||
|
||
suite.Assert().NoError(err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/talos-systems/go-smbios/smbios" | ||
) | ||
|
||
var ( | ||
syncSMBIOS sync.Once | ||
connSMBIOS *smbios.SMBIOS | ||
errSMBIOS error | ||
) | ||
|
||
// GetSMBIOSInfo returns the SMBIOS info. | ||
func GetSMBIOSInfo() (*smbios.SMBIOS, error) { | ||
syncSMBIOS.Do(func() { | ||
connSMBIOS, errSMBIOS = smbios.New() | ||
}) | ||
|
||
return connSMBIOS, errSMBIOS | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package hardware | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/cosi-project/runtime/pkg/controller" | ||
"github.com/cosi-project/runtime/pkg/resource" | ||
"github.com/talos-systems/go-smbios/smbios" | ||
"go.uber.org/zap" | ||
|
||
hwadapter "github.com/talos-systems/talos/internal/app/machined/pkg/adapters/hardware" | ||
"github.com/talos-systems/talos/pkg/machinery/resources/hardware" | ||
) | ||
|
||
// SystemInfoController populates CPU information of the underlying hardware. | ||
type SystemInfoController struct { | ||
SMBIOS *smbios.SMBIOS | ||
} | ||
|
||
// Name implements controller.Controller interface. | ||
func (ctrl *SystemInfoController) Name() string { | ||
return "hardware.SystemInfoController" | ||
} | ||
|
||
// Inputs implements controller.Controller interface. | ||
func (ctrl *SystemInfoController) Inputs() []controller.Input { | ||
return nil | ||
} | ||
|
||
// Outputs implements controller.Controller interface. | ||
func (ctrl *SystemInfoController) Outputs() []controller.Output { | ||
return []controller.Output{ | ||
{ | ||
Type: hardware.ProcessorType, | ||
Kind: controller.OutputExclusive, | ||
}, | ||
{ | ||
Type: hardware.MemoryType, | ||
Kind: controller.OutputExclusive, | ||
}, | ||
} | ||
} | ||
|
||
// Run implements controller.Controller interface. | ||
// | ||
//nolint:gocyclo | ||
func (ctrl *SystemInfoController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { | ||
select { | ||
case <-ctx.Done(): | ||
return nil | ||
case <-r.EventCh(): | ||
} | ||
|
||
// controller runs only once | ||
if ctrl.SMBIOS == nil { | ||
s, err := GetSMBIOSInfo() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
ctrl.SMBIOS = s | ||
} | ||
|
||
for _, p := range ctrl.SMBIOS.ProcessorInformation { | ||
// replaces `CPU 0` with `CPU-0` | ||
id := strings.ReplaceAll(p.SocketDesignation, " ", "-") | ||
|
||
if err := r.Modify(ctx, hardware.NewProcessorInfo(id), func(res resource.Resource) error { | ||
hwadapter.Processor(res.(*hardware.Processor)).Update(&p) | ||
|
||
return nil | ||
}); err != nil { | ||
return fmt.Errorf("error updating objects: %w", err) | ||
} | ||
} | ||
|
||
for _, m := range ctrl.SMBIOS.MemoryDevices { | ||
// replaces `SIMM 0` with `SIMM-0` | ||
id := strings.ReplaceAll(m.DeviceLocator, " ", "-") | ||
|
||
if err := r.Modify(ctx, hardware.NewMemoryInfo(id), func(res resource.Resource) error { | ||
hwadapter.Memory(res.(*hardware.Memory)).Update(&m) | ||
|
||
return nil | ||
}); err != nil { | ||
return fmt.Errorf("error updating objects: %w", err) | ||
} | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.