diff --git a/cmd/openshift-install/version.go b/cmd/openshift-install/version.go index 04824af70e4..c84ea444e26 100644 --- a/cmd/openshift-install/version.go +++ b/cmd/openshift-install/version.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "strings" "github.com/spf13/cobra" @@ -33,6 +34,14 @@ func runVersionCmd(cmd *cobra.Command, args []string) error { if image, err := releaseimage.Default(); err == nil { fmt.Printf("release image %s\n", image) } - fmt.Printf("release architecture %s\n", version.DefaultArch()) + releaseArch, err := version.ReleaseArchitecture() + if err != nil { + return err + } + fmt.Printf("release architecture %s\n", releaseArch) + if strings.Contains(releaseArch, "multi") || strings.Contains(releaseArch, "unknown") { + fmt.Printf("default architecture %s\n", version.DefaultArch()) + } + return nil } diff --git a/pkg/version/version.go b/pkg/version/version.go index 1e6e50a7ddb..730e553d99d 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -3,8 +3,11 @@ package version import ( "fmt" + "os" "strings" + "github.com/sirupsen/logrus" + "github.com/openshift/installer/pkg/types" ) @@ -34,12 +37,23 @@ var ( // Set in hack/build.sh. defaultArch = "amd64" + // releaseArchitecture is the architecture of the release payload: multi, amd64, arm64, ppc64le, or s390x. + // we don't know the releaseArchitecure by default "". + releaseArchitecture = "" + // defaultReleaseInfoPadded may be replaced in the binary with Release Metadata: Version that overrides defaultVersion as // a null-terminated string within the allowed character length. This allows a distributor to override the payload // location without having to rebuild the source. defaultVersionPadded = "\x00_RELEASE_VERSION_LOCATION_\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" defaultVersionPrefix = "\x00_RELEASE_VERSION_LOCATION_\x00" defaultVersionLength = len(defaultVersionPadded) + + // releaseArchitecturesPadded may be replaced in the binary with Release Image Architecture(s): RELEASE_ARCHITECTURE that overrides releaseArchitecture as + // a null-terminated string within the allowed character length. This allows a distributor to override the payload + // location without having to rebuild the source. + releaseArchitecturesPadded = "\x00_RELEASE_ARCHITECTURE_LOCATION_\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" + releaseArchitecturesPrefix = "\x00_RELEASE_ARCHITECTURE_LOCATION_\x00" + releaseArchitecturesLength = len(releaseArchitecturesPadded) ) // String returns the human-friendly representation of the version. @@ -71,6 +85,46 @@ func Version() (string, error) { return releaseName, nil } +// ReleaseArchitecture returns the release image cpu architecture version. +func ReleaseArchitecture() (string, error) { + ri, okRI := os.LookupEnv("OPENSHIFT_INSTALL_RELEASE_IMAGE_OVERRIDE") + if okRI { + logrus.Warnf("Found override for release image (%s). Release Image Architecture is unknown", ri) + return "unknown", nil + } + if strings.HasPrefix(releaseArchitecturesPadded, releaseArchitecturesPrefix) { + logrus.Warn("Release Image Architecture not detected. Release Image Architecture is unknown") + return "unknown", nil + } + nullTerminator := strings.IndexByte(releaseArchitecturesPadded, '\x00') + if nullTerminator == -1 { + // the binary has been altered, but we didn't find a null terminator within the release architecture constant which is an error + return Raw, fmt.Errorf("release architecture location was replaced but without a null terminator before %d bytes", releaseArchitecturesLength) + } + if nullTerminator > len(releaseArchitecturesPadded) { + // the binary has been altered, but the null terminator is *longer* than the constant encoded in the binary + return Raw, fmt.Errorf("release architecture location contains no null-terminator and constant is corrupted") + } + releaseArchitecture = releaseArchitecturesPadded[:nullTerminator] + if len(releaseArchitecture) == 0 { + // the binary has been altered, but the replaced release architecture is empty which is incorrect + return Raw, fmt.Errorf("release architecture was incorrectly replaced during extract") + } + return cleanArch(releaseArchitecture), nil +} + +// cleanArch oc will embed linux/ or multi (linux/) we want to clean this up so validation can more cleanly use this method. +// multi (linux/amd64) -> multi +// linux/amd64 -> amd64 +// linux/ -> . +func cleanArch(releaseArchitecture string) string { + if strings.HasPrefix(releaseArchitecture, "multi") { + return "multi" + } + // remove 'linux/', we just want + return strings.ReplaceAll(releaseArchitecture, "linux/", "") +} + // DefaultArch returns the default release architecture func DefaultArch() types.Architecture { return types.Architecture(defaultArch)