Skip to content

Commit d0cc21c

Browse files
authored
Merge pull request #132 from rollandf/preparegcc
feat: Go implement prepareGcc
2 parents 3f7bc00 + c7b8321 commit d0cc21c

File tree

3 files changed

+485
-2
lines changed

3 files changed

+485
-2
lines changed

entrypoint/internal/driver/driver.go

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23+
"regexp"
24+
"strconv"
25+
"strings"
2326

2427
"github.com/go-logr/logr"
2528

@@ -133,13 +136,190 @@ func (d *driverMgr) Clear(ctx context.Context) error {
133136
}
134137

135138
func (d *driverMgr) prepareGCC(ctx context.Context) error {
139+
log := logr.FromContextOrDiscard(ctx)
140+
141+
// Get OS type first to check if it's OpenShift
136142
osType, err := d.host.GetOSType(ctx)
143+
if err != nil {
144+
return fmt.Errorf("failed to get OS type: %w", err)
145+
}
146+
147+
// Check if OpenShift is detected - skip GCC setup for RHCOS/OpenShift
148+
if osType == constants.OSTypeOpenShift {
149+
log.V(1).Info("RHCOS detected (OpenShift), skipping GCC setup")
150+
return nil
151+
}
152+
153+
// Extract GCC version from /proc/version
154+
gccVersion, majorVersion, err := d.extractGCCInfo(ctx)
155+
if err != nil {
156+
return err
157+
}
158+
if gccVersion == "" {
159+
log.V(1).Info("Could not extract GCC version from /proc/version")
160+
return nil
161+
}
162+
163+
log.V(1).Info("Kernel compiled with GCC version", "version", gccVersion, "major", majorVersion)
164+
165+
// Install and configure GCC based on OS type
166+
gccBinary, kernelGCCVer, err := d.installGCCForOS(ctx, osType, majorVersion)
137167
if err != nil {
138168
return err
139169
}
140-
//nolint:gocritic
170+
171+
// Set up alternatives for GCC binary
172+
return d.setupGCCAlternatives(ctx, gccBinary, kernelGCCVer)
173+
}
174+
175+
// extractGCCInfo extracts GCC version information from /proc/version
176+
func (d *driverMgr) extractGCCInfo(ctx context.Context) (string, int, error) {
177+
log := logr.FromContextOrDiscard(ctx)
178+
179+
// Read /proc/version to extract GCC version
180+
procVersion, err := d.os.ReadFile("/proc/version")
181+
if err != nil {
182+
return "", 0, fmt.Errorf("failed to read /proc/version: %w", err)
183+
}
184+
185+
log.V(1).Info("Kernel version info", "proc_version", string(procVersion))
186+
187+
// Extract GCC version using regex
188+
gccVersion, err := d.extractGCCVersion(string(procVersion))
189+
if err != nil {
190+
log.V(1).Info("Could not extract GCC version from /proc/version", "error", err)
191+
return "", 0, nil // Not a fatal error, continue without GCC setup
192+
}
193+
194+
// Extract major version
195+
majorVersion, err := d.extractMajorVersion(gccVersion)
196+
if err != nil {
197+
return "", 0, fmt.Errorf("failed to extract major version from %s: %w", gccVersion, err)
198+
}
199+
200+
return gccVersion, majorVersion, nil
201+
}
202+
203+
// installGCCForOS installs GCC package based on OS type
204+
func (d *driverMgr) installGCCForOS(ctx context.Context, osType string, majorVersion int) (string, string, error) {
141205
switch osType {
142-
case "something":
206+
case constants.OSTypeUbuntu:
207+
return d.installGCCUbuntu(ctx, majorVersion)
208+
case constants.OSTypeSLES:
209+
return d.installGCCSLES(ctx, majorVersion)
210+
case constants.OSTypeRedHat:
211+
return d.installGCCRedHat(ctx, majorVersion)
212+
default:
213+
return "", "", fmt.Errorf("unsupported OS type: %s", osType)
214+
}
215+
}
216+
217+
// installGCCUbuntu installs GCC for Ubuntu
218+
func (d *driverMgr) installGCCUbuntu(ctx context.Context, majorVersion int) (string, string, error) {
219+
log := logr.FromContextOrDiscard(ctx)
220+
kernelGCCVer := fmt.Sprintf("gcc-%d", majorVersion)
221+
222+
log.V(1).Info("Installing GCC for Ubuntu", "package", kernelGCCVer)
223+
_, _, err := d.cmd.RunCommand(ctx, "apt-get", "-yq", "update")
224+
if err != nil {
225+
return "", "", fmt.Errorf("failed to update apt packages: %w", err)
143226
}
227+
_, _, err = d.cmd.RunCommand(ctx, "apt-get", "-yq", "install", kernelGCCVer)
228+
if err != nil {
229+
return "", "", fmt.Errorf("failed to install %s: %w", kernelGCCVer, err)
230+
}
231+
232+
gccBinary := fmt.Sprintf("/usr/bin/%s", kernelGCCVer)
233+
return gccBinary, kernelGCCVer, nil
234+
}
235+
236+
// installGCCSLES installs GCC for SLES
237+
func (d *driverMgr) installGCCSLES(ctx context.Context, majorVersion int) (string, string, error) {
238+
log := logr.FromContextOrDiscard(ctx)
239+
kernelGCCVerPackage := fmt.Sprintf("gcc%d", majorVersion)
240+
kernelGCCVerBin := fmt.Sprintf("gcc-%d", majorVersion)
241+
242+
log.V(1).Info("Installing GCC for SLES", "package", kernelGCCVerPackage)
243+
_, _, err := d.cmd.RunCommand(ctx, "zypper", "--non-interactive", "install", "--no-recommends", kernelGCCVerPackage)
244+
if err != nil {
245+
return "", "", fmt.Errorf("failed to install %s: %w", kernelGCCVerPackage, err)
246+
}
247+
248+
gccBinary := fmt.Sprintf("/usr/bin/%s", kernelGCCVerBin)
249+
return gccBinary, kernelGCCVerBin, nil
250+
}
251+
252+
// installGCCRedHat installs GCC for RedHat
253+
func (d *driverMgr) installGCCRedHat(ctx context.Context, majorVersion int) (string, string, error) {
254+
log := logr.FromContextOrDiscard(ctx)
255+
toolsetPackage := fmt.Sprintf("gcc-toolset-%d", majorVersion)
256+
257+
log.V(1).Info("Checking for gcc-toolset availability", "package", toolsetPackage)
258+
259+
// Check if gcc-toolset is available
260+
_, _, err := d.cmd.RunCommand(ctx, "dnf", "list", "available", toolsetPackage)
261+
if err == nil {
262+
// gcc-toolset version is available
263+
kernelGCCVer := fmt.Sprintf("gcc-toolset-%d-gcc", majorVersion)
264+
log.V(1).Info("Installing gcc-toolset for RedHat", "package", toolsetPackage)
265+
_, _, err = d.cmd.RunCommand(ctx, "dnf", "-q", "-y", "install", toolsetPackage)
266+
if err != nil {
267+
return "", "", fmt.Errorf("failed to install %s: %w", toolsetPackage, err)
268+
}
269+
gccBinary := fmt.Sprintf("/opt/rh/gcc-toolset-%d/root/usr/bin/gcc", majorVersion)
270+
return gccBinary, kernelGCCVer, nil
271+
}
272+
273+
// Fall back to default gcc package
274+
log.V(1).Info("gcc-toolset not available, using default gcc package")
275+
kernelGCCVer := "gcc"
276+
_, _, err = d.cmd.RunCommand(ctx, "dnf", "-q", "-y", "install", "gcc")
277+
if err != nil {
278+
return "", "", fmt.Errorf("failed to install gcc: %w", err)
279+
}
280+
gccBinary := "/usr/bin/gcc"
281+
return gccBinary, kernelGCCVer, nil
282+
}
283+
284+
// setupGCCAlternatives sets up GCC alternatives
285+
func (d *driverMgr) setupGCCAlternatives(ctx context.Context, gccBinary, kernelGCCVer string) error {
286+
log := logr.FromContextOrDiscard(ctx)
287+
altGCCPrio := 200
288+
289+
log.V(1).Info("Setting up GCC alternatives", "gcc_binary", gccBinary, "priority", altGCCPrio)
290+
_, _, err := d.cmd.RunCommand(ctx, "update-alternatives", "--install", "/usr/bin/gcc", "gcc", gccBinary, strconv.Itoa(altGCCPrio))
291+
if err != nil {
292+
return fmt.Errorf("failed to set up GCC alternatives: %w", err)
293+
}
294+
295+
log.Info("Set GCC for driver compilation, matching kernel compiled version", "version", kernelGCCVer)
144296
return nil
145297
}
298+
299+
// extractGCCVersion extracts GCC version from /proc/version string
300+
func (d *driverMgr) extractGCCVersion(procVersion string) (string, error) {
301+
// Regex to match gcc version pattern: gcc followed by optional non-digit characters and then version number
302+
re := regexp.MustCompile(`(?i)gcc[^0-9]*([0-9]+\.[0-9]+\.[0-9]+)`)
303+
matches := re.FindStringSubmatch(procVersion)
304+
305+
if len(matches) < 2 {
306+
return "", fmt.Errorf("no GCC version found in /proc/version")
307+
}
308+
309+
return matches[1], nil
310+
}
311+
312+
// extractMajorVersion extracts the major version number from a version string like "11.5.0"
313+
func (d *driverMgr) extractMajorVersion(version string) (int, error) {
314+
parts := strings.Split(version, ".")
315+
if len(parts) == 0 {
316+
return 0, fmt.Errorf("invalid version format: %s", version)
317+
}
318+
319+
major, err := strconv.Atoi(parts[0])
320+
if err != nil {
321+
return 0, fmt.Errorf("failed to parse major version from %s: %w", version, err)
322+
}
323+
324+
return major, nil
325+
}
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 driver
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
func TestDriver(t *testing.T) {
27+
RegisterFailHandler(Fail)
28+
RunSpecs(t, "Driver Suite")
29+
}

0 commit comments

Comments
 (0)