Skip to content

Commit b0e8cc5

Browse files
committed
PRODENG-3471: fix Windows MCR install for FIPS channels
For FIPS channels (e.g. stable-29.2.1/fips) the Windows MCR installer repo publishes versioned artifacts (docker-29.2.1+fips.zip) but does NOT publish docker-latest+fips.zip. Launchpad was hardcoding DOCKER_VERSION=latest, which caused the installer to construct a non-existent URL and exit 1 on all Windows nodes. Linux nodes were unaffected because the Linux installers use package-manager channels, not this download URL. Fix: add MCRConfig.WindowsInstallerVersion() which returns 'latest' for all non-FIPS channels (preserving current behaviour — only docker-latest.zip is published for non-FIPS) and extracts the version from the channel string for FIPS channels: stable-29.2.1/fips → 29.2.1 stable-29.4.1/fips → 29.4.1 test-29.4.1-rc3/fips → 29.4.1-rc3 The installer script appends +fips automatically when CHANNEL contains /fips, so only the numeric version needs to be supplied. Note: the ticket's proposed Version() method extracted the version for all versioned channels (e.g. stable-29.2 → 29.2), which would break non-FIPS installs since docker-29.2.zip is not published. WindowsInstallerVersion() guards on the /fips suffix to avoid this. Signed-off-by: James Nesbitt <jnesbitt@mirantis.com>
1 parent c691642 commit b0e8cc5

3 files changed

Lines changed: 62 additions & 1 deletion

File tree

pkg/configurer/windows.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (c WindowsConfigurer) InstallMCRLicense(h os.Host, lic string) error {
6060

6161
// InstallMCR install MCR on Windows.
6262
func (c WindowsConfigurer) InstallMCR(h os.Host, engineConfig commonconfig.MCRConfig) error {
63-
version := "latest"
63+
version := engineConfig.WindowsInstallerVersion()
6464

6565
installerPath, getInstallerErr := GetInstaller(engineConfig.InstallURLWindows)
6666
if getInstallerErr != nil {

pkg/product/common/config/mcr_config.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package config
22

33
import (
4+
"strings"
5+
46
"github.com/Mirantis/launchpad/pkg/constant"
57
)
68

@@ -70,3 +72,35 @@ func (c *MCRConfig) SetDefaults() {
7072
c.InstallURLWindows = constant.MCRInstallURLWindows
7173
}
7274
}
75+
76+
// WindowsInstallerVersion returns the version token to pass as DOCKER_VERSION
77+
// to the Windows MCR installer script (install.ps1).
78+
//
79+
// For non-FIPS channels (e.g. "stable-29.2", "stable-25.0") the installer
80+
// repo publishes only a single "docker-latest.zip" artifact, so "latest" is
81+
// always correct.
82+
//
83+
// For FIPS channels (e.g. "stable-29.2.1/fips") the repo publishes versioned
84+
// artifacts ("docker-29.2.1+fips.zip") but NOT a "docker-latest+fips.zip",
85+
// so the version must be extracted from the channel string. The installer
86+
// script appends "+fips" automatically when it detects the /fips suffix in
87+
// CHANNEL, so we only need to supply the numeric version here.
88+
func (c *MCRConfig) WindowsInstallerVersion() string {
89+
if !strings.HasSuffix(c.Channel, "/fips") {
90+
return "latest"
91+
}
92+
// Strip the /fips suffix, then walk the dash-separated parts looking for
93+
// the first segment that starts with a digit — that is the version.
94+
// e.g. "stable-29.2.1/fips" → "stable-29.2.1" → ["stable","29.2.1"] → "29.2.1"
95+
// e.g. "test-29.4.1-rc3/fips" → "test-29.4.1-rc3" → ["test","29.4.1-rc3"] → "29.4.1-rc3"
96+
ch := strings.TrimSuffix(c.Channel, "/fips")
97+
parts := strings.Split(ch, "-")
98+
for i, p := range parts {
99+
if len(p) > 0 && p[0] >= '0' && p[0] <= '9' {
100+
return strings.Join(parts[i:], "-")
101+
}
102+
}
103+
// FIPS channel with no parseable version — fall back to latest and let the
104+
// installer fail with a clear error rather than silently downloading wrong.
105+
return "latest"
106+
}

pkg/product/common/config/mcr_config_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,30 @@ func TestSwarmUpdateCommands(t *testing.T) {
3030
require.Equal(t, 1, slices.Index(cfg.SwarmUpdateCommands, "command2"))
3131
require.Equal(t, 2, slices.Index(cfg.SwarmUpdateCommands, "command3"))
3232
}
33+
34+
func TestWindowsInstallerVersion(t *testing.T) {
35+
tests := []struct {
36+
channel string
37+
want string
38+
}{
39+
// Standard channels — always "latest" regardless of minor version
40+
{"stable-29.2", "latest"},
41+
{"stable-25.0", "latest"},
42+
{"ee-stable-29.2", "latest"},
43+
// FIPS channels — version extracted from channel string
44+
{"stable-29.2.1/fips", "29.2.1"},
45+
{"stable-29.4.1/fips", "29.4.1"},
46+
{"test-29.4.1/fips", "29.4.1"},
47+
// FIPS RC channel — full version including rc suffix
48+
{"test-29.4.1-rc3/fips", "29.4.1-rc3"},
49+
// FIPS channel with no version — falls back to latest
50+
{"stable/fips", "latest"},
51+
}
52+
for _, tt := range tests {
53+
t.Run(tt.channel, func(t *testing.T) {
54+
cfg := commonconfig.MCRConfig{Channel: tt.channel}
55+
got := cfg.WindowsInstallerVersion()
56+
require.Equal(t, tt.want, got, "channel=%q", tt.channel)
57+
})
58+
}
59+
}

0 commit comments

Comments
 (0)