Skip to content

Commit d8df547

Browse files
committed
feat: Go support for OS discovery
Signed-off-by: Fred Rolland <[email protected]>
1 parent c6f0dc7 commit d8df547

File tree

12 files changed

+782
-11
lines changed

12 files changed

+782
-11
lines changed

entrypoint/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ $(BUILDDIR):
4242

4343
##@ Binary Dependencies download
4444
MOCKERY ?= $(LOCALBIN)/mockery
45-
MOCKERY_VERSION ?= v2.46.3
45+
MOCKERY_VERSION ?= v2.53.3
4646
.PHONY: mockery
4747
mockery: $(MOCKERY) ## Download mockery locally if necessary.
4848
$(MOCKERY): | $(LOCALBIN)

entrypoint/internal/constants/constants.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,14 @@ const (
2121

2222
DriverContainerModeSources = "sources"
2323
DriverContainerModePrecompiled = "precompiled"
24+
25+
// OS Types
26+
OSTypeUbuntu = "ubuntu"
27+
OSTypeSLES = "sles"
28+
OSTypeRedHat = "redhat"
29+
OSTypeOpenShift = "openshift"
30+
31+
// Default versions
32+
DefaultRHELVersion = "8.4"
33+
DefaultOpenShiftVersion = "4.9"
2434
)

entrypoint/internal/driver/mocks/Interface.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

entrypoint/internal/netconfig/mocks/Interface.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

entrypoint/internal/utils/cmd/mocks/Interface.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

entrypoint/internal/utils/host/host.go

Lines changed: 163 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ package host
1818

1919
import (
2020
"context"
21+
"fmt"
22+
"regexp"
23+
"strconv"
24+
"strings"
25+
"sync"
2126

27+
"github.com/Mellanox/doca-driver-build/entrypoint/internal/constants"
2228
"github.com/Mellanox/doca-driver-build/entrypoint/internal/utils/cmd"
2329
"github.com/Mellanox/doca-driver-build/entrypoint/internal/wrappers"
2430
)
@@ -31,6 +37,17 @@ func New(c cmd.Interface, osWrapper wrappers.OSWrapper) Interface {
3137
}
3238
}
3339

40+
// RedhatVersionInfo contains version information for RedHat-based distributions
41+
type RedhatVersionInfo struct {
42+
// MajorVersion is the major version number (e.g., 8, 9)
43+
MajorVersion int
44+
// FullVersion is the complete version string (e.g., "8.4", "9.2")
45+
FullVersion string
46+
// OpenShiftVersion is the OpenShift version if running on RHCOS (e.g., "4.9")
47+
// If empty, this is not RHCOS
48+
OpenShiftVersion string
49+
}
50+
3451
// Interface is the interface exposed by the host package.
3552
type Interface interface {
3653
// GetOSType returns the name of the operating system as a string.
@@ -42,17 +59,68 @@ type Interface interface {
4259
LsMod(ctx context.Context) (map[string]LoadedModule, error)
4360
// RmMod unload the kernel module.
4461
RmMod(ctx context.Context, module string) error
62+
// GetRedHatVersionInfo parses RedHat version information from /host/etc/os-release
63+
// and returns version details. Should only be called for RedHat-based distributions.
64+
GetRedHatVersionInfo(ctx context.Context) (*RedhatVersionInfo, error)
4565
}
4666

4767
type host struct {
4868
cmd cmd.Interface
4969
os wrappers.OSWrapper
70+
71+
// Cache for OS type
72+
osTypeCache struct {
73+
value string
74+
err error
75+
once sync.Once
76+
}
77+
78+
// Cache for RedHat version info
79+
redhatVersionCache struct {
80+
value *RedhatVersionInfo
81+
err error
82+
once sync.Once
83+
}
5084
}
5185

5286
// GetOSType is the default implementation of the host.Interface.
5387
func (h *host) GetOSType(ctx context.Context) (string, error) {
54-
// TODO: add implementation
55-
return "", nil
88+
h.osTypeCache.once.Do(func() {
89+
// Read /etc/os-release file to determine OS type
90+
osReleaseContent, err := h.os.ReadFile("/etc/os-release")
91+
if err != nil {
92+
h.osTypeCache.err = err
93+
return
94+
}
95+
96+
osReleaseStr := string(osReleaseContent)
97+
osReleaseStr = strings.ToLower(osReleaseStr)
98+
99+
// Check for Ubuntu (case insensitive)
100+
if strings.Contains(osReleaseStr, "ubuntu") {
101+
h.osTypeCache.value = constants.OSTypeUbuntu
102+
return
103+
}
104+
105+
// Check for SLES (case insensitive)
106+
if strings.Contains(osReleaseStr, "sles") {
107+
h.osTypeCache.value = constants.OSTypeSLES
108+
return
109+
}
110+
111+
// Default to redhat for other distributions (RHEL, CentOS, Fedora, etc.)
112+
h.osTypeCache.value = constants.OSTypeRedHat
113+
114+
// Build the redhatVersionCache for RedHat-based systems
115+
h.buildRedHatVersionCache()
116+
117+
// Check if this is actually an OpenShift system (has OpenShift version)
118+
if h.redhatVersionCache.value != nil && h.redhatVersionCache.value.OpenShiftVersion != "" {
119+
h.osTypeCache.value = constants.OSTypeOpenShift
120+
}
121+
})
122+
123+
return h.osTypeCache.value, h.osTypeCache.err
56124
}
57125

58126
// GetDebugInfo is the default implementation of the host.Interface.
@@ -67,7 +135,7 @@ type LoadedModule struct {
67135
Name string
68136
// RefCount amount of refs to the module.
69137
RefCount int
70-
// UseBy contains names of the modules that depends on this module.
138+
// UsedBy contains names of the modules that depends on this module.
71139
UsedBy []string
72140
}
73141

@@ -83,3 +151,95 @@ func (h *host) RmMod(ctx context.Context, module string) error {
83151
// TODO: add implementation
84152
return nil
85153
}
154+
155+
// buildRedHatVersionCache builds the RedHat version cache by parsing /host/etc/os-release
156+
func (h *host) buildRedHatVersionCache() {
157+
// Read /host/etc/os-release file
158+
osReleaseContent, err := h.os.ReadFile("/host/etc/os-release")
159+
if err != nil {
160+
h.redhatVersionCache.err = fmt.Errorf("failed to read /host/etc/os-release: %w", err)
161+
return
162+
}
163+
164+
osReleaseStr := string(osReleaseContent)
165+
166+
// Parse the os-release content
167+
versionInfo := &RedhatVersionInfo{}
168+
169+
// Extract ID, VERSION_ID, RHEL_VERSION, and OPENSHIFT_VERSION
170+
var id, versionID, rhelVersion, openshiftVersion string
171+
172+
idMatch := regexp.MustCompile(`(?m)^ID=(.+)$`).FindStringSubmatch(osReleaseStr)
173+
if len(idMatch) > 1 {
174+
id = strings.Trim(idMatch[1], `"`)
175+
}
176+
177+
versionIDMatch := regexp.MustCompile(`(?m)^VERSION_ID=(.+)$`).FindStringSubmatch(osReleaseStr)
178+
if len(versionIDMatch) > 1 {
179+
versionID = strings.Trim(versionIDMatch[1], `"`)
180+
}
181+
182+
rhelVersionMatch := regexp.MustCompile(`(?m)^RHEL_VERSION=(.+)$`).FindStringSubmatch(osReleaseStr)
183+
if len(rhelVersionMatch) > 1 {
184+
rhelVersion = strings.Trim(rhelVersionMatch[1], `"`)
185+
}
186+
187+
openshiftVersionMatch := regexp.MustCompile(`(?m)^OPENSHIFT_VERSION=(.+)$`).FindStringSubmatch(osReleaseStr)
188+
if len(openshiftVersionMatch) > 1 {
189+
openshiftVersion = strings.Trim(openshiftVersionMatch[1], `"`)
190+
}
191+
192+
if id == "rhcos" {
193+
// This is RHCOS - use OpenShift version logic
194+
if openshiftVersion != "" {
195+
versionInfo.OpenShiftVersion = openshiftVersion
196+
} else {
197+
versionInfo.OpenShiftVersion = versionID
198+
}
199+
if versionInfo.OpenShiftVersion == "" {
200+
versionInfo.OpenShiftVersion = constants.DefaultOpenShiftVersion
201+
}
202+
versionInfo.FullVersion = versionInfo.OpenShiftVersion
203+
} else {
204+
// For RHEL and other RedHat-based distros (CentOS, Fedora, etc.)
205+
versionInfo.FullVersion = rhelVersion
206+
if versionInfo.FullVersion == "" {
207+
versionInfo.FullVersion = versionID
208+
}
209+
if versionInfo.FullVersion == "" {
210+
versionInfo.FullVersion = constants.DefaultRHELVersion
211+
}
212+
213+
// If OPENSHIFT_VERSION is present, this might be RHCOS with ID=rhel
214+
if openshiftVersion != "" {
215+
versionInfo.OpenShiftVersion = openshiftVersion
216+
}
217+
}
218+
219+
// Extract major version from full version
220+
majorVersionStr := strings.Split(versionInfo.FullVersion, ".")[0]
221+
majorVersion, err := strconv.Atoi(majorVersionStr)
222+
if err != nil {
223+
h.redhatVersionCache.err = fmt.Errorf("failed to parse major version from '%s': %w", versionInfo.FullVersion, err)
224+
return
225+
}
226+
versionInfo.MajorVersion = majorVersion
227+
228+
h.redhatVersionCache.value = versionInfo
229+
}
230+
231+
// GetRedHatVersionInfo is the default implementation of the host.Interface.
232+
func (h *host) GetRedHatVersionInfo(ctx context.Context) (*RedhatVersionInfo, error) {
233+
// First check if this is a RedHat-based system
234+
osType, err := h.GetOSType(ctx)
235+
if err != nil {
236+
return nil, fmt.Errorf("failed to get OS type: %w", err)
237+
}
238+
239+
if osType != constants.OSTypeRedHat && osType != constants.OSTypeOpenShift {
240+
return nil, fmt.Errorf("GetRedHatVersionInfo should only be called for RedHat-based distributions, got: %s", osType)
241+
}
242+
243+
// Return the cached RedHat version info (built during GetOSType)
244+
return h.redhatVersionCache.value, h.redhatVersionCache.err
245+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2025, NVIDIA CORPORATION & AFFILIATES
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package host
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
func TestHost(t *testing.T) {
27+
RegisterFailHandler(Fail)
28+
RunSpecs(t, "Host Suite")
29+
}

0 commit comments

Comments
 (0)