github.com/openshift/installer@v1.4.17/pkg/version/version.go (about) 1 // Package version includes the version information for installer. 2 package version 3 4 import ( 5 "fmt" 6 "os" 7 "strings" 8 9 "github.com/sirupsen/logrus" 10 11 "github.com/openshift/installer/pkg/types" 12 ) 13 14 // This file handles correctly identifying the default release version, which is expected to be 15 // replaced in the binary post-compile by the release name extracted from a payload. The expected modification is: 16 // 17 // 1. Extract a release binary from the installer image referenced within the release image 18 // 2. Identify the release name, add a NUL terminator byte (0x00) to the end, calculate length 19 // 3. Length must be less than the marker length 20 // 4. Search through the installer binary looking for `\x00_RELEASE_VERSION_LOCATION_\x00<PADDING_TO_LENGTH>` 21 // where padding is the ASCII character X and length is the total length of the marker 22 // 5. Overwrite the beginning of the marker with the release name and a NUL terminator byte (0x00) 23 24 var ( 25 // Raw is the string representation of the version. This will be replaced 26 // with the calculated version at build time. 27 // set in hack/build.sh 28 Raw = "was not built correctly" 29 30 // Commit is the commit hash from which the installer was built. 31 // Set in hack/build.sh. 32 Commit = "" 33 34 // defaultArch is the payload architecture for which the installer was built, 35 // which even on Linux may not be the same as the architecture of the 36 // installer binary itself. 37 // Set in hack/build.sh. 38 defaultArch = "amd64" 39 40 // releaseArchitecture is the architecture of the release payload: multi, amd64, arm64, ppc64le, or s390x. 41 // we don't know the releaseArchitecure by default "". 42 releaseArchitecture = "" 43 44 // defaultReleaseInfoPadded may be replaced in the binary with Release Metadata: Version that overrides defaultVersion as 45 // a null-terminated string within the allowed character length. This allows a distributor to override the payload 46 // location without having to rebuild the source. 47 defaultVersionPadded = "\x00_RELEASE_VERSION_LOCATION_\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" 48 defaultVersionPrefix = "\x00_RELEASE_VERSION_LOCATION_\x00" 49 defaultVersionLength = len(defaultVersionPadded) 50 51 // releaseArchitecturesPadded may be replaced in the binary with Release Image Architecture(s): RELEASE_ARCHITECTURE that overrides releaseArchitecture as 52 // a null-terminated string within the allowed character length. This allows a distributor to override the payload 53 // location without having to rebuild the source. 54 releaseArchitecturesPadded = "\x00_RELEASE_ARCHITECTURE_LOCATION_\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00" 55 releaseArchitecturesPrefix = "\x00_RELEASE_ARCHITECTURE_LOCATION_\x00" 56 releaseArchitecturesLength = len(releaseArchitecturesPadded) 57 ) 58 59 // String returns the human-friendly representation of the version. 60 func String() (string, error) { 61 version, err := Version() 62 return fmt.Sprintf("OpenShift Installer %s", version), err 63 } 64 65 // Version returns the installer/release version. 66 func Version() (string, error) { 67 if strings.HasPrefix(defaultVersionPadded, defaultVersionPrefix) { 68 return Raw, nil 69 } 70 nullTerminator := strings.IndexByte(defaultVersionPadded, '\x00') 71 if nullTerminator == -1 { 72 // the binary has been altered, but we didn't find a null terminator within the release name constant which is an error 73 return Raw, fmt.Errorf("release name location was replaced but without a null terminator before %d bytes", defaultVersionLength) 74 } 75 if nullTerminator > len(defaultVersionPadded) { 76 // the binary has been altered, but the null terminator is *longer* than the constant encoded in the binary 77 return Raw, fmt.Errorf("release name location contains no null-terminator and constant is corrupted") 78 } 79 releaseName := defaultVersionPadded[:nullTerminator] 80 if len(releaseName) == 0 { 81 // the binary has been altered, but the replaced release name is empty which is incorrect 82 // the oc binary will not be pinned to Release Metadata:Version 83 return Raw, fmt.Errorf("release name was incorrectly replaced during extract") 84 } 85 return releaseName, nil 86 } 87 88 // ReleaseArchitecture returns the release image cpu architecture version. 89 func ReleaseArchitecture() (string, error) { 90 ri, okRI := os.LookupEnv("OPENSHIFT_INSTALL_RELEASE_IMAGE_OVERRIDE") 91 if okRI { 92 logrus.Warnf("Found override for release image (%s). Release Image Architecture is unknown", ri) 93 return "unknown", nil 94 } 95 if strings.HasPrefix(releaseArchitecturesPadded, releaseArchitecturesPrefix) { 96 logrus.Warn("Release Image Architecture not detected. Release Image Architecture is unknown") 97 return "unknown", nil 98 } 99 nullTerminator := strings.IndexByte(releaseArchitecturesPadded, '\x00') 100 if nullTerminator == -1 { 101 // the binary has been altered, but we didn't find a null terminator within the release architecture constant which is an error 102 return Raw, fmt.Errorf("release architecture location was replaced but without a null terminator before %d bytes", releaseArchitecturesLength) 103 } 104 if nullTerminator > len(releaseArchitecturesPadded) { 105 // the binary has been altered, but the null terminator is *longer* than the constant encoded in the binary 106 return Raw, fmt.Errorf("release architecture location contains no null-terminator and constant is corrupted") 107 } 108 releaseArchitecture = releaseArchitecturesPadded[:nullTerminator] 109 if len(releaseArchitecture) == 0 { 110 // the binary has been altered, but the replaced release architecture is empty which is incorrect 111 return Raw, fmt.Errorf("release architecture was incorrectly replaced during extract") 112 } 113 return cleanArch(releaseArchitecture), nil 114 } 115 116 // cleanArch oc will embed linux/<arch> or multi (linux/<arch>) we want to clean this up so validation can more cleanly use this method. 117 // multi (linux/amd64) -> multi 118 // linux/amd64 -> amd64 119 // linux/<arch> -> <arch>. 120 func cleanArch(releaseArchitecture string) string { 121 if strings.HasPrefix(releaseArchitecture, "multi") { 122 return "multi" 123 } 124 // remove 'linux/', we just want <arch> 125 return strings.ReplaceAll(releaseArchitecture, "linux/", "") 126 } 127 128 // DefaultArch returns the default release architecture 129 func DefaultArch() types.Architecture { 130 return types.Architecture(defaultArch) 131 }