diff --git a/internal/app/machined/pkg/adapters/hardware/hardware.go b/internal/app/machined/pkg/adapters/hardware/hardware.go new file mode 100644 index 0000000000..268abf9b1c --- /dev/null +++ b/internal/app/machined/pkg/adapters/hardware/hardware.go @@ -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 diff --git a/internal/app/machined/pkg/adapters/hardware/memory.go b/internal/app/machined/pkg/adapters/hardware/memory.go new file mode 100644 index 0000000000..0c668fc747 --- /dev/null +++ b/internal/app/machined/pkg/adapters/hardware/memory.go @@ -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) +} diff --git a/internal/app/machined/pkg/adapters/hardware/processor.go b/internal/app/machined/pkg/adapters/hardware/processor.go new file mode 100644 index 0000000000..b72362f69e --- /dev/null +++ b/internal/app/machined/pkg/adapters/hardware/processor.go @@ -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) +} diff --git a/internal/app/machined/pkg/controllers/hardware/hardware.go b/internal/app/machined/pkg/controllers/hardware/hardware.go new file mode 100644 index 0000000000..c0e3a629e4 --- /dev/null +++ b/internal/app/machined/pkg/controllers/hardware/hardware.go @@ -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 diff --git a/internal/app/machined/pkg/controllers/hardware/hardware_test.go b/internal/app/machined/pkg/controllers/hardware/hardware_test.go new file mode 100644 index 0000000000..a2ca6b3df6 --- /dev/null +++ b/internal/app/machined/pkg/controllers/hardware/hardware_test.go @@ -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) +} diff --git a/internal/app/machined/pkg/controllers/hardware/smbios.go b/internal/app/machined/pkg/controllers/hardware/smbios.go new file mode 100644 index 0000000000..3fc4b8eba3 --- /dev/null +++ b/internal/app/machined/pkg/controllers/hardware/smbios.go @@ -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 +} diff --git a/internal/app/machined/pkg/controllers/hardware/system.go b/internal/app/machined/pkg/controllers/hardware/system.go new file mode 100644 index 0000000000..81eb5015b2 --- /dev/null +++ b/internal/app/machined/pkg/controllers/hardware/system.go @@ -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 +} diff --git a/internal/app/machined/pkg/controllers/hardware/system_test.go b/internal/app/machined/pkg/controllers/hardware/system_test.go new file mode 100644 index 0000000000..279340118c --- /dev/null +++ b/internal/app/machined/pkg/controllers/hardware/system_test.go @@ -0,0 +1,139 @@ +// 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 ( + "fmt" + "os" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/stretchr/testify/suite" + "github.com/talos-systems/go-retry/retry" + "github.com/talos-systems/go-smbios/smbios" + + hardwarectrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/hardware" + "github.com/talos-systems/talos/pkg/machinery/resources/hardware" +) + +type SystemInfoSuite struct { + HardwareSuite +} + +func (suite *SystemInfoSuite) TestPopulateSystemInformation() { + stream, err := os.Open("testdata/SuperMicro-Dual-Xeon.dmi") + suite.Require().NoError(err) + + //nolint: errcheck + defer stream.Close() + + version := smbios.Version{Major: 3, Minor: 3, Revision: 0} // dummy version + s, err := smbios.Decode(stream, version) + suite.Require().NoError(err) + + suite.Require().NoError( + suite.runtime.RegisterController( + &hardwarectrl.SystemInfoController{ + SMBIOS: s, + }, + ), + ) + + suite.startRuntime() + + cpuSpecs := map[string]hardware.ProcessorSpec{ + "CPU-1": { + Socket: "CPU 1", + Manufacturer: "Intel", + ProductName: "Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz", + MaxSpeed: 4000, + BootSpeed: 2600, + Status: 65, + AssetTag: "3A65E8E29D76BF8D", + CoreCount: 8, + CoreEnabled: 8, + ThreadCount: 16, + }, + "CPU-2": { + Socket: "CPU 2", + Manufacturer: "Intel", + ProductName: "Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz", + MaxSpeed: 4000, + BootSpeed: 2600, + Status: 65, + CoreCount: 8, + CoreEnabled: 8, + ThreadCount: 16, + }, + } + + memorySpecs := map[string]hardware.MemorySpec{ + "P1-DIMMA1": { + Size: 4096, + DeviceLocator: "P1-DIMMA1", + BankLocator: "P0_Node0_Channel0_Dimm0", + Speed: 1333, + Manufacturer: "Micron", + SerialNumber: "346C4A12", + AssetTag: "Dimm0_AssetTag", + ProductName: "18KSF51272PZ-1G4K", + }, + "P1-DIMMA2": { + Size: 4096, + DeviceLocator: "P1-DIMMA2", + BankLocator: "P0_Node0_Channel0_Dimm1", + Speed: 1333, + Manufacturer: "Kingston", + SerialNumber: "D2166C8B", + AssetTag: "Dimm1_AssetTag", + ProductName: "HP647647-071-HYE", + }, + } + + for k, v := range cpuSpecs { + suite.Assert().NoError( + retry.Constant(1*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + suite.assertResource(*hardware.NewProcessorInfo(k).Metadata(), func(r resource.Resource) error { + status := *r.(*hardware.Processor).TypedSpec() + if !suite.Assert().Equal(v, status) { + return retry.ExpectedError(fmt.Errorf("cpu status doesn't match: %v != %v", v, status)) + } + + return nil + }), + ), + ) + } + + for k, v := range memorySpecs { + suite.Assert().NoError( + retry.Constant(1*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + suite.assertResource(*hardware.NewMemoryInfo(k).Metadata(), func(r resource.Resource) error { + status := *r.(*hardware.Memory).TypedSpec() + if !suite.Assert().Equal(v, status) { + return retry.ExpectedError(fmt.Errorf("memory status doesn't match: %v != %v", v, status)) + } + + return nil + }), + ), + ) + } +} + +func TestSystemInfoSyncSuite(t *testing.T) { + suite.Run(t, new(SystemInfoSuite)) +} + +func (suite *SystemInfoSuite) startRuntime() { + suite.wg.Add(1) + + go func() { + defer suite.wg.Done() + + suite.Assert().NoError(suite.runtime.Run(suite.ctx)) + }() +} diff --git a/internal/app/machined/pkg/controllers/hardware/testdata/SuperMicro-Dual-Xeon.dmi b/internal/app/machined/pkg/controllers/hardware/testdata/SuperMicro-Dual-Xeon.dmi new file mode 100644 index 0000000000..cb515d3e8b Binary files /dev/null and b/internal/app/machined/pkg/controllers/hardware/testdata/SuperMicro-Dual-Xeon.dmi differ diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index 2f9a3caaad..81652e5eaf 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -22,6 +22,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/cluster" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/config" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/files" + "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/hardware" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/kubespan" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/network" @@ -107,6 +108,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error EtcPath: "/etc", ShadowPath: constants.SystemEtcPath, }, + &hardware.SystemInfoController{}, &k8s.ControlPlaneStaticPodController{}, &k8s.EndpointController{}, &k8s.ExtraManifestController{}, diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go index 95a394d319..90d5230d1d 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go @@ -17,6 +17,7 @@ import ( "github.com/talos-systems/talos/pkg/machinery/resources/cluster" "github.com/talos-systems/talos/pkg/machinery/resources/config" "github.com/talos-systems/talos/pkg/machinery/resources/files" + "github.com/talos-systems/talos/pkg/machinery/resources/hardware" "github.com/talos-systems/talos/pkg/machinery/resources/k8s" "github.com/talos-systems/talos/pkg/machinery/resources/kubespan" "github.com/talos-systems/talos/pkg/machinery/resources/network" @@ -63,6 +64,7 @@ func NewState() (*State, error) { {cluster.RawNamespaceName, "Cluster unmerged raw resources."}, {config.NamespaceName, "Talos node configuration."}, {files.NamespaceName, "Files and file-like resources."}, + {hardware.NamespaceName, "Hardware resources."}, {k8s.NamespaceName, "Kubernetes all node types resources."}, {k8s.ControlPlaneNamespaceName, "Kubernetes control plane resources."}, {kubespan.NamespaceName, "KubeSpan resources."}, @@ -87,6 +89,8 @@ func NewState() (*State, error) { &config.MachineType{}, &files.EtcFileSpec{}, &files.EtcFileStatus{}, + &hardware.Processor{}, + &hardware.Memory{}, &k8s.AdmissionControlConfig{}, &k8s.APIServerConfig{}, &k8s.ConfigStatus{}, diff --git a/pkg/machinery/resources/hardware/deep_copy.generated.go b/pkg/machinery/resources/hardware/deep_copy.generated.go new file mode 100644 index 0000000000..01837744ff --- /dev/null +++ b/pkg/machinery/resources/hardware/deep_copy.generated.go @@ -0,0 +1,19 @@ +// 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/. + +// Code generated by "deep-copy -type ProcessorSpec -type MemorySpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. + +package hardware + +// DeepCopy generates a deep copy of ProcessorSpec. +func (o ProcessorSpec) DeepCopy() ProcessorSpec { + var cp ProcessorSpec = o + return cp +} + +// DeepCopy generates a deep copy of MemorySpec. +func (o MemorySpec) DeepCopy() MemorySpec { + var cp MemorySpec = o + return cp +} diff --git a/pkg/machinery/resources/hardware/hardware.go b/pkg/machinery/resources/hardware/hardware.go new file mode 100644 index 0000000000..4b9aa5ad52 --- /dev/null +++ b/pkg/machinery/resources/hardware/hardware.go @@ -0,0 +1,14 @@ +// 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/cosi-project/runtime/pkg/resource" +) + +//go:generate deep-copy -type ProcessorSpec -type MemorySpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . + +// NamespaceName contains resources related to hardware as a whole. +const NamespaceName resource.Namespace = "hardware" diff --git a/pkg/machinery/resources/hardware/hardware_test.go b/pkg/machinery/resources/hardware/hardware_test.go new file mode 100644 index 0000000000..41f41b3c37 --- /dev/null +++ b/pkg/machinery/resources/hardware/hardware_test.go @@ -0,0 +1,33 @@ +// 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" + "testing" + + "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/cosi-project/runtime/pkg/state/registry" + "github.com/stretchr/testify/assert" + + "github.com/talos-systems/talos/pkg/machinery/resources/hardware" +) + +func TestRegisterResource(t *testing.T) { + ctx := context.TODO() + + resources := state.WrapCore(namespaced.NewState(inmem.Build)) + resourceRegistry := registry.NewResourceRegistry(resources) + + for _, resource := range []resource.Resource{ + &hardware.Processor{}, + &hardware.Memory{}, + } { + assert.NoError(t, resourceRegistry.Register(ctx, resource)) + } +} diff --git a/pkg/machinery/resources/hardware/memory.go b/pkg/machinery/resources/hardware/memory.go new file mode 100644 index 0000000000..e160ef75e1 --- /dev/null +++ b/pkg/machinery/resources/hardware/memory.go @@ -0,0 +1,66 @@ +// 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/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/typed" +) + +// MemoryType is type of Memory resource. +const MemoryType = resource.Type("Memories.hardware.talos.dev") + +// Memory resource holds node Memory information. +type Memory = typed.Resource[MemorySpec, MemoryRD] + +// MemorySpec represents a single Memory. +type MemorySpec struct { + Size uint32 `yaml:"sizeMiB,omitempty"` + DeviceLocator string `yaml:"deviceLocator,omitempty"` + BankLocator string `yaml:"bankLocator,omitempty"` + Speed uint32 `yaml:"speed,omitempty"` + Manufacturer string `yaml:"manufacturer,omitempty"` + SerialNumber string `yaml:"serialNumber,omitempty"` + AssetTag string `yaml:"assetTag,omitempty"` + ProductName string `yaml:"productName,omitempty"` +} + +// NewMemoryInfo initializes a MemoryInfo resource. +func NewMemoryInfo(id string) *Memory { + return typed.NewResource[MemorySpec, MemoryRD]( + resource.NewMetadata(NamespaceName, MemoryType, id, resource.VersionUndefined), + MemorySpec{}, + ) +} + +// MemoryRD provides auxiliary methods for Memory info. +type MemoryRD struct{} + +// ResourceDefinition implements typed.ResourceDefinition interface. +func (c MemoryRD) ResourceDefinition(resource.Metadata, MemorySpec) meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: MemoryType, + Aliases: []resource.Type{ + "memory", + "ram", + }, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Manufacturer", + JSONPath: `{.manufacturer}`, + }, + { + Name: "Model", + JSONPath: `{.productName}`, + }, + { + Name: "SizeMiB", + JSONPath: `{.sizeMiB}`, + }, + }, + } +} diff --git a/pkg/machinery/resources/hardware/processor.go b/pkg/machinery/resources/hardware/processor.go new file mode 100644 index 0000000000..8d12804b0c --- /dev/null +++ b/pkg/machinery/resources/hardware/processor.go @@ -0,0 +1,76 @@ +// 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/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/typed" +) + +// ProcessorType is type of Processor resource. +const ProcessorType = resource.Type("Processors.hardware.talos.dev") + +// Processor resource holds node Processor information. +type Processor = typed.Resource[ProcessorSpec, ProcessorRD] + +// ProcessorSpec represents a single processor. +type ProcessorSpec struct { + Socket string `yaml:"socket,omitempty"` + Manufacturer string `yaml:"manufacturer,omitempty"` + ProductName string `yaml:"productName,omitempty"` + // MaxSpeed is in megahertz (Mhz) + MaxSpeed uint32 `yaml:"maxSpeedMhz,omitempty"` + // Speed is in megahertz (Mhz) + BootSpeed uint32 `yaml:"bootSpeedMhz,omitempty"` + Status uint32 `yaml:"status,omitempty"` + SerialNumber string `yaml:"serialNumber,omitempty"` + AssetTag string `yaml:"assetTag,omitempty"` + PartNumber string `yaml:"partNumber,omitempty"` + CoreCount uint32 `yaml:"coreCount,omitempty"` + CoreEnabled uint32 `yaml:"coreEnabled,omitempty"` + ThreadCount uint32 `yaml:"threadCount,omitempty"` +} + +// NewProcessorInfo initializes a ProcessorInfo resource. +func NewProcessorInfo(id string) *Processor { + return typed.NewResource[ProcessorSpec, ProcessorRD]( + resource.NewMetadata(NamespaceName, ProcessorType, id, resource.VersionUndefined), + ProcessorSpec{}, + ) +} + +// ProcessorRD provides auxiliary methods for Processor info. +type ProcessorRD struct{} + +// ResourceDefinition implements typed.ResourceDefinition interface. +func (c ProcessorRD) ResourceDefinition(resource.Metadata, ProcessorSpec) meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: ProcessorType, + Aliases: []resource.Type{ + "cpus", + "cpu", + }, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Manufacturer", + JSONPath: `{.manufacturer}`, + }, + { + Name: "Model", + JSONPath: `{.productName}`, + }, + { + Name: "Cores", + JSONPath: `{.coreCount}`, + }, + { + Name: "Threads", + JSONPath: `{.threadCount}`, + }, + }, + } +} diff --git a/pkg/machinery/resources/secrets/deep_copy.generated.go b/pkg/machinery/resources/secrets/deep_copy.generated.go index 71c2ea2c21..d3386e3425 100644 --- a/pkg/machinery/resources/secrets/deep_copy.generated.go +++ b/pkg/machinery/resources/secrets/deep_copy.generated.go @@ -7,9 +7,10 @@ package secrets import ( - "inet.af/netaddr" "net" "net/url" + + "inet.af/netaddr" ) // DeepCopy generates a deep copy of APICertsSpec.