Skip to content

Commit 0d5ca7f

Browse files
authored
Merge pull request #141 from rollandf/updateca
feat: Go update CA certificates
2 parents fa1b034 + 0dd4233 commit 0d5ca7f

File tree

2 files changed

+331
-0
lines changed

2 files changed

+331
-0
lines changed

entrypoint/internal/driver/driver.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ type driverMgr struct {
8484
// PreStart is the default implementation of the driver.Interface.
8585
func (d *driverMgr) PreStart(ctx context.Context) error {
8686
log := logr.FromContextOrDiscard(ctx)
87+
88+
// Update CA certificates at the very beginning
89+
if err := d.updateCACertificates(ctx); err != nil {
90+
log.V(1).Info("Failed to update CA certificates", "error", err)
91+
// Non-fatal error, continue
92+
}
93+
8794
switch d.containerMode {
8895
case constants.DriverContainerModeSources:
8996
log.Info("Executing driver sources container")
@@ -1566,3 +1573,61 @@ func (d *driverMgr) installRedHatDependencies(ctx context.Context, versionInfo *
15661573

15671574
return nil
15681575
}
1576+
1577+
// updateCACertificates updates system CA certificates for supported OS types
1578+
func (d *driverMgr) updateCACertificates(ctx context.Context) error {
1579+
log := logr.FromContextOrDiscard(ctx)
1580+
1581+
// Constants for CA certificate update commands
1582+
const updateCaCertificatesCmd = "update-ca-certificates"
1583+
const updateCaTrustCmd = "update-ca-trust extract"
1584+
1585+
// Get OS type to determine the appropriate CA certificate update command
1586+
osType, err := d.host.GetOSType(ctx)
1587+
if err != nil {
1588+
return fmt.Errorf("failed to get OS type: %w", err)
1589+
}
1590+
1591+
// Determine the command and log message based on OS type
1592+
var command string
1593+
var logMessage string
1594+
1595+
switch osType {
1596+
case constants.OSTypeUbuntu:
1597+
command = updateCaCertificatesCmd
1598+
logMessage = "Updating system CA certificates (Ubuntu)..."
1599+
case constants.OSTypeSLES:
1600+
command = updateCaCertificatesCmd
1601+
logMessage = "Updating system CA certificates (SLES)..."
1602+
case constants.OSTypeRedHat, constants.OSTypeOpenShift:
1603+
command = updateCaTrustCmd
1604+
logMessage = "Updating system CA certificates (RHEL/OpenShift)..."
1605+
default:
1606+
log.V(1).Info("Skipping CA certificate update for unsupported OS", "os", osType)
1607+
return nil
1608+
}
1609+
1610+
log.Info(logMessage)
1611+
1612+
// Extract the base command for existence check (remove arguments)
1613+
baseCommand := strings.Fields(command)[0]
1614+
1615+
// Check if the command exists using shell with 'command -v'
1616+
_, _, err = d.cmd.RunCommand(ctx, "sh", "-c", "command -v "+baseCommand)
1617+
if err != nil {
1618+
log.Info("[WARN] CA certificate update command not found", "command", baseCommand)
1619+
// Command not found is not a fatal error, continue execution
1620+
return nil //nolint:nilerr // Intentionally ignoring error - command not found is not fatal
1621+
}
1622+
1623+
// Run the appropriate command with || true to ignore errors
1624+
// This matches the bash script pattern: exec_cmd "command || true"
1625+
_, _, err = d.cmd.RunCommand(ctx, "sh", "-c", command+" || true")
1626+
if err != nil {
1627+
log.V(1).Info("CA certificate update command failed", "command", command, "error", err)
1628+
// Non-fatal error, continue
1629+
}
1630+
1631+
log.V(1).Info("CA certificate update completed", "os", osType)
1632+
return nil
1633+
}

entrypoint/internal/driver/driver_test.go

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ var _ = Describe("Driver", func() {
8181
})
8282

8383
It("should succeed when all required fields are set", func() {
84+
// Mock updateCACertificates call
85+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
86+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
87+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
88+
89+
// Mock the main PreStart logic
8490
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
8591
osMock.EXPECT().ReadFile("/proc/version").Return([]byte("Linux version 5.4.0-74-generic (buildd@lcy01-amd64-001) (gcc version 11.5.0) #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021"), nil)
8692
cmdMock.EXPECT().RunCommand(ctx, "apt-get", "-yq", "update").Return("", "", nil)
@@ -95,6 +101,11 @@ var _ = Describe("Driver", func() {
95101
cfg.NvidiaNicDriverPath = ""
96102
dm = New(constants.DriverContainerModeSources, cfg, cmdMock, hostMock, osMock).(*driverMgr)
97103

104+
// Mock updateCACertificates call
105+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
106+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
107+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
108+
98109
err := dm.PreStart(ctx)
99110
Expect(err).To(HaveOccurred())
100111
Expect(err.Error()).To(ContainSubstring("NVIDIA_NIC_DRIVER_PATH environment variable must be set"))
@@ -106,6 +117,12 @@ var _ = Describe("Driver", func() {
106117
cfg.NvidiaNicDriversInventoryPath = inventoryDir
107118
dm = New(constants.DriverContainerModeSources, cfg, cmdMock, hostMock, osMock).(*driverMgr)
108119

120+
// Mock updateCACertificates call
121+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
122+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
123+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
124+
125+
// Mock the main PreStart logic
109126
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
110127
osMock.EXPECT().ReadFile("/proc/version").Return([]byte("Linux version 5.4.0-74-generic (buildd@lcy01-amd64-001) (gcc version 11.5.0) #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021"), nil)
111128
cmdMock.EXPECT().RunCommand(ctx, "apt-get", "-yq", "update").Return("", "", nil)
@@ -122,6 +139,12 @@ var _ = Describe("Driver", func() {
122139
cfg.NvidiaNicDriversInventoryPath = inventoryFile
123140
dm = New(constants.DriverContainerModeSources, cfg, cmdMock, hostMock, osMock).(*driverMgr)
124141

142+
// Mock updateCACertificates call
143+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
144+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
145+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
146+
147+
// Mock the main PreStart logic
125148
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
126149
osMock.EXPECT().ReadFile("/proc/version").Return([]byte("Linux version 5.4.0-74-generic (buildd@lcy01-amd64-001) (gcc version 11.5.0) #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021"), nil)
127150
cmdMock.EXPECT().RunCommand(ctx, "apt-get", "-yq", "update").Return("", "", nil)
@@ -137,6 +160,12 @@ var _ = Describe("Driver", func() {
137160
cfg.NvidiaNicDriversInventoryPath = "/nonexistent/path"
138161
dm = New(constants.DriverContainerModeSources, cfg, cmdMock, hostMock, osMock).(*driverMgr)
139162

163+
// Mock updateCACertificates call
164+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
165+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
166+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
167+
168+
// Mock the main PreStart logic
140169
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
141170
osMock.EXPECT().ReadFile("/proc/version").Return([]byte("Linux version 5.4.0-74-generic (buildd@lcy01-amd64-001) (gcc version 11.5.0) #83-Ubuntu SMP Sat May 8 02:35:39 UTC 2021"), nil)
142171
cmdMock.EXPECT().RunCommand(ctx, "apt-get", "-yq", "update").Return("", "", nil)
@@ -155,6 +184,11 @@ var _ = Describe("Driver", func() {
155184
})
156185

157186
It("should succeed without additional validation", func() {
187+
// Mock updateCACertificates call
188+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
189+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
190+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
191+
158192
err := dm.PreStart(ctx)
159193
Expect(err).NotTo(HaveOccurred())
160194
})
@@ -166,6 +200,11 @@ var _ = Describe("Driver", func() {
166200
})
167201

168202
It("should return an error", func() {
203+
// Mock updateCACertificates call
204+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
205+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
206+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
207+
169208
err := dm.PreStart(ctx)
170209
Expect(err).To(HaveOccurred())
171210
Expect(err.Error()).To(ContainSubstring("unknown containerMode"))
@@ -1999,6 +2038,233 @@ var _ = Describe("Driver", func() {
19992038
Expect(err).NotTo(HaveOccurred())
20002039
})
20012040
})
2041+
2042+
Context("updateCACertificates", func() {
2043+
BeforeEach(func() {
2044+
dm = New(constants.DriverContainerModeSources, cfg, cmdMock, hostMock, osMock).(*driverMgr)
2045+
})
2046+
2047+
It("should update CA certificates successfully for Ubuntu", func() {
2048+
// Mock GetOSType to return Ubuntu
2049+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
2050+
2051+
// Mock command existence check
2052+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
2053+
2054+
// Mock CA certificate update command
2055+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
2056+
2057+
err := dm.updateCACertificates(ctx)
2058+
Expect(err).NotTo(HaveOccurred())
2059+
})
2060+
2061+
It("should update CA certificates successfully for SLES", func() {
2062+
// Mock GetOSType to return SLES
2063+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeSLES, nil)
2064+
2065+
// Mock command existence check
2066+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
2067+
2068+
// Mock CA certificate update command
2069+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
2070+
2071+
err := dm.updateCACertificates(ctx)
2072+
Expect(err).NotTo(HaveOccurred())
2073+
})
2074+
2075+
It("should update CA certificates successfully for RedHat", func() {
2076+
// Mock GetOSType to return RedHat
2077+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeRedHat, nil)
2078+
2079+
// Mock command existence check for update-ca-trust
2080+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2081+
2082+
// Mock CA certificate update command
2083+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", nil)
2084+
2085+
err := dm.updateCACertificates(ctx)
2086+
Expect(err).NotTo(HaveOccurred())
2087+
})
2088+
2089+
It("should update CA certificates successfully for OpenShift", func() {
2090+
// Mock GetOSType to return OpenShift
2091+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeOpenShift, nil)
2092+
2093+
// Mock command existence check for update-ca-trust
2094+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2095+
2096+
// Mock CA certificate update command
2097+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", nil)
2098+
2099+
err := dm.updateCACertificates(ctx)
2100+
Expect(err).NotTo(HaveOccurred())
2101+
})
2102+
2103+
It("should skip CA certificate update for unsupported OS", func() {
2104+
// Mock GetOSType to return unsupported OS
2105+
hostMock.EXPECT().GetOSType(ctx).Return("unsupported", nil)
2106+
2107+
// No command execution should happen
2108+
err := dm.updateCACertificates(ctx)
2109+
Expect(err).NotTo(HaveOccurred())
2110+
})
2111+
2112+
It("should return error when GetOSType fails", func() {
2113+
expectedError := errors.New("failed to get OS type")
2114+
hostMock.EXPECT().GetOSType(ctx).Return("", expectedError)
2115+
2116+
err := dm.updateCACertificates(ctx)
2117+
Expect(err).To(HaveOccurred())
2118+
Expect(err.Error()).To(ContainSubstring("failed to get OS type"))
2119+
})
2120+
2121+
It("should handle command not found gracefully for Ubuntu", func() {
2122+
// Mock GetOSType to return Ubuntu
2123+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
2124+
2125+
// Mock command existence check failure
2126+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", errors.New("command not found"))
2127+
2128+
// No CA certificate update command should be executed
2129+
err := dm.updateCACertificates(ctx)
2130+
Expect(err).NotTo(HaveOccurred())
2131+
})
2132+
2133+
It("should handle command not found gracefully for RedHat", func() {
2134+
// Mock GetOSType to return RedHat
2135+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeRedHat, nil)
2136+
2137+
// Mock command existence check failure
2138+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", errors.New("command not found"))
2139+
2140+
// No CA certificate update command should be executed
2141+
err := dm.updateCACertificates(ctx)
2142+
Expect(err).NotTo(HaveOccurred())
2143+
})
2144+
2145+
It("should handle CA certificate update command failure gracefully for Ubuntu", func() {
2146+
// Mock GetOSType to return Ubuntu
2147+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
2148+
2149+
// Mock command existence check
2150+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
2151+
2152+
// Mock CA certificate update command failure
2153+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", errors.New("update failed"))
2154+
2155+
// Should not return error (non-fatal)
2156+
err := dm.updateCACertificates(ctx)
2157+
Expect(err).NotTo(HaveOccurred())
2158+
})
2159+
2160+
It("should handle CA certificate update command failure gracefully for RedHat", func() {
2161+
// Mock GetOSType to return RedHat
2162+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeRedHat, nil)
2163+
2164+
// Mock command existence check
2165+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2166+
2167+
// Mock CA certificate update command failure
2168+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", errors.New("update failed"))
2169+
2170+
// Should not return error (non-fatal)
2171+
err := dm.updateCACertificates(ctx)
2172+
Expect(err).NotTo(HaveOccurred())
2173+
})
2174+
2175+
It("should handle CA certificate update command failure gracefully for SLES", func() {
2176+
// Mock GetOSType to return SLES
2177+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeSLES, nil)
2178+
2179+
// Mock command existence check
2180+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
2181+
2182+
// Mock CA certificate update command failure
2183+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", errors.New("update failed"))
2184+
2185+
// Should not return error (non-fatal)
2186+
err := dm.updateCACertificates(ctx)
2187+
Expect(err).NotTo(HaveOccurred())
2188+
})
2189+
2190+
It("should handle CA certificate update command failure gracefully for OpenShift", func() {
2191+
// Mock GetOSType to return OpenShift
2192+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeOpenShift, nil)
2193+
2194+
// Mock command existence check
2195+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2196+
2197+
// Mock CA certificate update command failure
2198+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", errors.New("update failed"))
2199+
2200+
// Should not return error (non-fatal)
2201+
err := dm.updateCACertificates(ctx)
2202+
Expect(err).NotTo(HaveOccurred())
2203+
})
2204+
2205+
It("should use correct command for Ubuntu with arguments", func() {
2206+
// Mock GetOSType to return Ubuntu
2207+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeUbuntu, nil)
2208+
2209+
// Mock command existence check
2210+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-certificates").Return("", "", nil)
2211+
2212+
// Mock CA certificate update command - verify the exact command
2213+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-certificates || true").Return("", "", nil)
2214+
2215+
err := dm.updateCACertificates(ctx)
2216+
Expect(err).NotTo(HaveOccurred())
2217+
})
2218+
2219+
It("should use correct command for RedHat with arguments", func() {
2220+
// Mock GetOSType to return RedHat
2221+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeRedHat, nil)
2222+
2223+
// Mock command existence check
2224+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2225+
2226+
// Mock CA certificate update command - verify the exact command
2227+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", nil)
2228+
2229+
err := dm.updateCACertificates(ctx)
2230+
Expect(err).NotTo(HaveOccurred())
2231+
})
2232+
2233+
It("should extract base command correctly from command with arguments", func() {
2234+
// This test verifies that strings.Fields(command)[0] works correctly
2235+
// for extracting the base command from "update-ca-trust extract"
2236+
2237+
// Mock GetOSType to return RedHat
2238+
hostMock.EXPECT().GetOSType(ctx).Return(constants.OSTypeRedHat, nil)
2239+
2240+
// Mock command existence check - should check for "update-ca-trust" (base command)
2241+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "command -v update-ca-trust").Return("", "", nil)
2242+
2243+
// Mock CA certificate update command - should use full command with arguments
2244+
cmdMock.EXPECT().RunCommand(ctx, "sh", "-c", "update-ca-trust extract || true").Return("", "", nil)
2245+
2246+
err := dm.updateCACertificates(ctx)
2247+
Expect(err).NotTo(HaveOccurred())
2248+
})
2249+
2250+
It("should handle empty OS type gracefully", func() {
2251+
// Mock GetOSType to return empty string
2252+
hostMock.EXPECT().GetOSType(ctx).Return("", nil)
2253+
2254+
// No command execution should happen
2255+
err := dm.updateCACertificates(ctx)
2256+
Expect(err).NotTo(HaveOccurred())
2257+
})
2258+
2259+
It("should handle nil OS type gracefully", func() {
2260+
// Mock GetOSType to return empty string (nil would be handled by the interface)
2261+
hostMock.EXPECT().GetOSType(ctx).Return("", nil)
2262+
2263+
// No command execution should happen
2264+
err := dm.updateCACertificates(ctx)
2265+
Expect(err).NotTo(HaveOccurred())
2266+
})
2267+
})
20022268
})
20032269

20042270
var _ = Describe("Driver OFED Blacklist", func() {

0 commit comments

Comments
 (0)