mirror of
https://github.com/clearml/go-nvlib
synced 2025-04-07 06:14:03 +00:00
Refactor info API
This change adds a PropertyExtractor interface to encapsulate functions that query a system for certain capabilities. The IsTegraSystem has been renamed to HasTegraFiles function and marked as Deprecated. Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
parent
2560bf6332
commit
791d093c62
34
pkg/nvlib/info/api.go
Normal file
34
pkg/nvlib/info/api.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
package info
|
||||||
|
|
||||||
|
// Interface provides the API to the info package.
|
||||||
|
type Interface interface {
|
||||||
|
PropertyExtractor
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropertyExtractor provides a set of functions to query capabilities of the
|
||||||
|
// system.
|
||||||
|
//
|
||||||
|
//go:generate moq -rm -out property-extractor_mock.go . PropertyExtractor
|
||||||
|
type PropertyExtractor interface {
|
||||||
|
HasDXCore() (bool, string)
|
||||||
|
HasNvml() (bool, string)
|
||||||
|
HasTegraFiles() (bool, string)
|
||||||
|
// Deprecated: Use HasTegraFiles instead.
|
||||||
|
IsTegraSystem() (bool, string)
|
||||||
|
}
|
35
pkg/nvlib/info/builder.go
Normal file
35
pkg/nvlib/info/builder.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
package info
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
root root
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of the 'info' Interface.
|
||||||
|
func New(opts ...Option) Interface {
|
||||||
|
o := &options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(o)
|
||||||
|
}
|
||||||
|
if o.root == "" {
|
||||||
|
o.root = "/"
|
||||||
|
}
|
||||||
|
return &propertyExtractor{
|
||||||
|
root: o.root,
|
||||||
|
}
|
||||||
|
}
|
@ -17,23 +17,11 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
// Option defines a function for passing options to the New() call.
|
// Option defines a function for passing options to the New() call.
|
||||||
type Option func(*infolib)
|
type Option func(*options)
|
||||||
|
|
||||||
// New creates a new instance of the 'info' interface.
|
|
||||||
func New(opts ...Option) Interface {
|
|
||||||
i := &infolib{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(i)
|
|
||||||
}
|
|
||||||
if i.root == "" {
|
|
||||||
i.root = "/"
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRoot provides a Option to set the root of the 'info' interface.
|
// WithRoot provides a Option to set the root of the 'info' interface.
|
||||||
func WithRoot(root string) Option {
|
func WithRoot(r string) Option {
|
||||||
return func(i *infolib) {
|
return func(i *options) {
|
||||||
i.root = root
|
i.root = root(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,31 +19,21 @@ package info
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/NVIDIA/go-nvml/pkg/dl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface provides the API to the info package.
|
type propertyExtractor struct {
|
||||||
type Interface interface {
|
root root
|
||||||
HasDXCore() (bool, string)
|
|
||||||
HasNvml() (bool, string)
|
|
||||||
IsTegraSystem() (bool, string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type infolib struct {
|
var _ Interface = &propertyExtractor{}
|
||||||
root string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Interface = &infolib{}
|
|
||||||
|
|
||||||
// HasDXCore returns true if DXCore is detected on the system.
|
// HasDXCore returns true if DXCore is detected on the system.
|
||||||
func (i *infolib) HasDXCore() (bool, string) {
|
func (i *propertyExtractor) HasDXCore() (bool, string) {
|
||||||
const (
|
const (
|
||||||
libraryName = "libdxcore.so"
|
libraryName = "libdxcore.so"
|
||||||
)
|
)
|
||||||
if err := assertHasLibrary(libraryName); err != nil {
|
if err := i.root.assertHasLibrary(libraryName); err != nil {
|
||||||
return false, fmt.Sprintf("could not load DXCore library: %v", err)
|
return false, fmt.Sprintf("could not load DXCore library: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +41,11 @@ func (i *infolib) HasDXCore() (bool, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasNvml returns true if NVML is detected on the system.
|
// HasNvml returns true if NVML is detected on the system.
|
||||||
func (i *infolib) HasNvml() (bool, string) {
|
func (i *propertyExtractor) HasNvml() (bool, string) {
|
||||||
const (
|
const (
|
||||||
libraryName = "libnvidia-ml.so.1"
|
libraryName = "libnvidia-ml.so.1"
|
||||||
)
|
)
|
||||||
if err := assertHasLibrary(libraryName); err != nil {
|
if err := i.root.assertHasLibrary(libraryName); err != nil {
|
||||||
return false, fmt.Sprintf("could not load NVML library: %v", err)
|
return false, fmt.Sprintf("could not load NVML library: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +53,15 @@ func (i *infolib) HasNvml() (bool, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsTegraSystem returns true if the system is detected as a Tegra-based system.
|
// IsTegraSystem returns true if the system is detected as a Tegra-based system.
|
||||||
func (i *infolib) IsTegraSystem() (bool, string) {
|
// Deprecated: Use HasTegraFiles instead.
|
||||||
tegraReleaseFile := filepath.Join(i.root, "/etc/nv_tegra_release")
|
func (i *propertyExtractor) IsTegraSystem() (bool, string) {
|
||||||
tegraFamilyFile := filepath.Join(i.root, "/sys/devices/soc0/family")
|
return i.HasTegraFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasTegraFiles returns true if tegra-based files are detected on the system.
|
||||||
|
func (i *propertyExtractor) HasTegraFiles() (bool, string) {
|
||||||
|
tegraReleaseFile := i.root.join("/etc/nv_tegra_release")
|
||||||
|
tegraFamilyFile := i.root.join("/sys/devices/soc0/family")
|
||||||
|
|
||||||
if info, err := os.Stat(tegraReleaseFile); err == nil && !info.IsDir() {
|
if info, err := os.Stat(tegraReleaseFile); err == nil && !info.IsDir() {
|
||||||
return true, fmt.Sprintf("%v found", tegraReleaseFile)
|
return true, fmt.Sprintf("%v found", tegraReleaseFile)
|
||||||
@ -86,17 +82,3 @@ func (i *infolib) IsTegraSystem() (bool, string) {
|
|||||||
|
|
||||||
return false, fmt.Sprintf("%v has no 'tegra' prefix", tegraFamilyFile)
|
return false, fmt.Sprintf("%v has no 'tegra' prefix", tegraFamilyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// assertHasLibrary returns an error if the specified library cannot be loaded.
|
|
||||||
func assertHasLibrary(libraryName string) error {
|
|
||||||
const (
|
|
||||||
libraryLoadFlags = dl.RTLD_LAZY
|
|
||||||
)
|
|
||||||
lib := dl.New(libraryName, libraryLoadFlags)
|
|
||||||
if err := lib.Open(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer lib.Close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
178
pkg/nvlib/info/property-extractor_mock.go
Normal file
178
pkg/nvlib/info/property-extractor_mock.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
// Code generated by moq; DO NOT EDIT.
|
||||||
|
// github.com/matryer/moq
|
||||||
|
|
||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure, that PropertyExtractorMock does implement PropertyExtractor.
|
||||||
|
// If this is not the case, regenerate this file with moq.
|
||||||
|
var _ PropertyExtractor = &PropertyExtractorMock{}
|
||||||
|
|
||||||
|
// PropertyExtractorMock is a mock implementation of PropertyExtractor.
|
||||||
|
//
|
||||||
|
// func TestSomethingThatUsesPropertyExtractor(t *testing.T) {
|
||||||
|
//
|
||||||
|
// // make and configure a mocked PropertyExtractor
|
||||||
|
// mockedPropertyExtractor := &PropertyExtractorMock{
|
||||||
|
// HasDXCoreFunc: func() (bool, string) {
|
||||||
|
// panic("mock out the HasDXCore method")
|
||||||
|
// },
|
||||||
|
// HasNvmlFunc: func() (bool, string) {
|
||||||
|
// panic("mock out the HasNvml method")
|
||||||
|
// },
|
||||||
|
// HasTegraFilesFunc: func() (bool, string) {
|
||||||
|
// panic("mock out the HasTegraFiles method")
|
||||||
|
// },
|
||||||
|
// IsTegraSystemFunc: func() (bool, string) {
|
||||||
|
// panic("mock out the IsTegraSystem method")
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // use mockedPropertyExtractor in code that requires PropertyExtractor
|
||||||
|
// // and then make assertions.
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
type PropertyExtractorMock struct {
|
||||||
|
// HasDXCoreFunc mocks the HasDXCore method.
|
||||||
|
HasDXCoreFunc func() (bool, string)
|
||||||
|
|
||||||
|
// HasNvmlFunc mocks the HasNvml method.
|
||||||
|
HasNvmlFunc func() (bool, string)
|
||||||
|
|
||||||
|
// HasTegraFilesFunc mocks the HasTegraFiles method.
|
||||||
|
HasTegraFilesFunc func() (bool, string)
|
||||||
|
|
||||||
|
// IsTegraSystemFunc mocks the IsTegraSystem method.
|
||||||
|
IsTegraSystemFunc func() (bool, string)
|
||||||
|
|
||||||
|
// calls tracks calls to the methods.
|
||||||
|
calls struct {
|
||||||
|
// HasDXCore holds details about calls to the HasDXCore method.
|
||||||
|
HasDXCore []struct {
|
||||||
|
}
|
||||||
|
// HasNvml holds details about calls to the HasNvml method.
|
||||||
|
HasNvml []struct {
|
||||||
|
}
|
||||||
|
// HasTegraFiles holds details about calls to the HasTegraFiles method.
|
||||||
|
HasTegraFiles []struct {
|
||||||
|
}
|
||||||
|
// IsTegraSystem holds details about calls to the IsTegraSystem method.
|
||||||
|
IsTegraSystem []struct {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lockHasDXCore sync.RWMutex
|
||||||
|
lockHasNvml sync.RWMutex
|
||||||
|
lockHasTegraFiles sync.RWMutex
|
||||||
|
lockIsTegraSystem sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasDXCore calls HasDXCoreFunc.
|
||||||
|
func (mock *PropertyExtractorMock) HasDXCore() (bool, string) {
|
||||||
|
if mock.HasDXCoreFunc == nil {
|
||||||
|
panic("PropertyExtractorMock.HasDXCoreFunc: method is nil but PropertyExtractor.HasDXCore was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
}{}
|
||||||
|
mock.lockHasDXCore.Lock()
|
||||||
|
mock.calls.HasDXCore = append(mock.calls.HasDXCore, callInfo)
|
||||||
|
mock.lockHasDXCore.Unlock()
|
||||||
|
return mock.HasDXCoreFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasDXCoreCalls gets all the calls that were made to HasDXCore.
|
||||||
|
// Check the length with:
|
||||||
|
//
|
||||||
|
// len(mockedPropertyExtractor.HasDXCoreCalls())
|
||||||
|
func (mock *PropertyExtractorMock) HasDXCoreCalls() []struct {
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
}
|
||||||
|
mock.lockHasDXCore.RLock()
|
||||||
|
calls = mock.calls.HasDXCore
|
||||||
|
mock.lockHasDXCore.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasNvml calls HasNvmlFunc.
|
||||||
|
func (mock *PropertyExtractorMock) HasNvml() (bool, string) {
|
||||||
|
if mock.HasNvmlFunc == nil {
|
||||||
|
panic("PropertyExtractorMock.HasNvmlFunc: method is nil but PropertyExtractor.HasNvml was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
}{}
|
||||||
|
mock.lockHasNvml.Lock()
|
||||||
|
mock.calls.HasNvml = append(mock.calls.HasNvml, callInfo)
|
||||||
|
mock.lockHasNvml.Unlock()
|
||||||
|
return mock.HasNvmlFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasNvmlCalls gets all the calls that were made to HasNvml.
|
||||||
|
// Check the length with:
|
||||||
|
//
|
||||||
|
// len(mockedPropertyExtractor.HasNvmlCalls())
|
||||||
|
func (mock *PropertyExtractorMock) HasNvmlCalls() []struct {
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
}
|
||||||
|
mock.lockHasNvml.RLock()
|
||||||
|
calls = mock.calls.HasNvml
|
||||||
|
mock.lockHasNvml.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasTegraFiles calls HasTegraFilesFunc.
|
||||||
|
func (mock *PropertyExtractorMock) HasTegraFiles() (bool, string) {
|
||||||
|
if mock.HasTegraFilesFunc == nil {
|
||||||
|
panic("PropertyExtractorMock.HasTegraFilesFunc: method is nil but PropertyExtractor.HasTegraFiles was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
}{}
|
||||||
|
mock.lockHasTegraFiles.Lock()
|
||||||
|
mock.calls.HasTegraFiles = append(mock.calls.HasTegraFiles, callInfo)
|
||||||
|
mock.lockHasTegraFiles.Unlock()
|
||||||
|
return mock.HasTegraFilesFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasTegraFilesCalls gets all the calls that were made to HasTegraFiles.
|
||||||
|
// Check the length with:
|
||||||
|
//
|
||||||
|
// len(mockedPropertyExtractor.HasTegraFilesCalls())
|
||||||
|
func (mock *PropertyExtractorMock) HasTegraFilesCalls() []struct {
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
}
|
||||||
|
mock.lockHasTegraFiles.RLock()
|
||||||
|
calls = mock.calls.HasTegraFiles
|
||||||
|
mock.lockHasTegraFiles.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTegraSystem calls IsTegraSystemFunc.
|
||||||
|
func (mock *PropertyExtractorMock) IsTegraSystem() (bool, string) {
|
||||||
|
if mock.IsTegraSystemFunc == nil {
|
||||||
|
panic("PropertyExtractorMock.IsTegraSystemFunc: method is nil but PropertyExtractor.IsTegraSystem was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
}{}
|
||||||
|
mock.lockIsTegraSystem.Lock()
|
||||||
|
mock.calls.IsTegraSystem = append(mock.calls.IsTegraSystem, callInfo)
|
||||||
|
mock.lockIsTegraSystem.Unlock()
|
||||||
|
return mock.IsTegraSystemFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTegraSystemCalls gets all the calls that were made to IsTegraSystem.
|
||||||
|
// Check the length with:
|
||||||
|
//
|
||||||
|
// len(mockedPropertyExtractor.IsTegraSystemCalls())
|
||||||
|
func (mock *PropertyExtractorMock) IsTegraSystemCalls() []struct {
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
}
|
||||||
|
mock.lockIsTegraSystem.RLock()
|
||||||
|
calls = mock.calls.IsTegraSystem
|
||||||
|
mock.lockIsTegraSystem.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
86
pkg/nvlib/info/root.go
Normal file
86
pkg/nvlib/info/root.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/go-nvml/pkg/dl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// root represents a directory on the filesystem relative to which libraries
|
||||||
|
// such as the NVIDIA driver libraries can be found.
|
||||||
|
type root string
|
||||||
|
|
||||||
|
func (r root) join(parts ...string) string {
|
||||||
|
return filepath.Join(append([]string{string(r)}, parts...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertHasLibrary returns an error if the specified library cannot be loaded.
|
||||||
|
func (r root) assertHasLibrary(libraryName string) error {
|
||||||
|
const (
|
||||||
|
libraryLoadFlags = dl.RTLD_LAZY
|
||||||
|
)
|
||||||
|
lib := dl.New(r.tryResolveLibrary(libraryName), libraryLoadFlags)
|
||||||
|
if err := lib.Open(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer lib.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryResolveLibrary attempts to locate the specified library in the root.
|
||||||
|
// If the root is not specified, is "/", or the library cannot be found in the
|
||||||
|
// set of predefined paths, the input is returned as is.
|
||||||
|
func (r root) tryResolveLibrary(libraryName string) string {
|
||||||
|
if r == "" || r == "/" {
|
||||||
|
return libraryName
|
||||||
|
}
|
||||||
|
|
||||||
|
librarySearchPaths := []string{
|
||||||
|
"/usr/lib64",
|
||||||
|
"/usr/lib/x86_64-linux-gnu",
|
||||||
|
"/usr/lib/aarch64-linux-gnu",
|
||||||
|
"/lib64",
|
||||||
|
"/lib/x86_64-linux-gnu",
|
||||||
|
"/lib/aarch64-linux-gnu",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range librarySearchPaths {
|
||||||
|
l := r.join(d, libraryName)
|
||||||
|
resolved, err := resolveLink(l)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
return libraryName
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveLink finds the target of a symlink or the file itself in the
|
||||||
|
// case of a regular file.
|
||||||
|
// This is equivalent to running `readlink -f ${l}`.
|
||||||
|
func resolveLink(l string) (string, error) {
|
||||||
|
resolved, err := filepath.EvalSymlinks(l)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error resolving link '%v': %w", l, err)
|
||||||
|
}
|
||||||
|
return resolved, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user