diff --git a/pkg/asset/installconfig/aws/platform.go b/pkg/asset/installconfig/aws/platform.go index bda29d76927..e9ee9a9469f 100644 --- a/pkg/asset/installconfig/aws/platform.go +++ b/pkg/asset/installconfig/aws/platform.go @@ -11,13 +11,13 @@ import ( "github.com/sirupsen/logrus" "github.com/openshift/installer/pkg/rhcos" + "github.com/openshift/installer/pkg/types" "github.com/openshift/installer/pkg/types/aws" - "github.com/openshift/installer/pkg/version" ) // Platform collects AWS-specific configuration. func Platform(ctx context.Context) (*aws.Platform, error) { - architecture := version.DefaultArch() + architecture := types.DefaultArch() regions, err := knownPublicRegions(architecture, rhcos.DefaultOSImageStream) if err != nil { return nil, fmt.Errorf("failed to get AWS public regions: %w", err) diff --git a/pkg/asset/rhcos/iso.go b/pkg/asset/rhcos/iso.go index a38f86f38a9..87c9c090496 100644 --- a/pkg/asset/rhcos/iso.go +++ b/pkg/asset/rhcos/iso.go @@ -57,7 +57,7 @@ func GetMetalArtifact(ctx context.Context, archName string) (stream.PlatformArti ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - st, err := rhcos.FetchCoreOSBuild(ctx, rhcos.DefaultOSImageStream) + st, err := rhcos.FetchCoreOSBuild(ctx, types.OSImageStreamRHCOS9) if err != nil { return stream.PlatformArtifacts{}, err } diff --git a/pkg/asset/rhcos/releaseextract.go b/pkg/asset/rhcos/releaseextract.go index 4f8d0f6a640..7a4e3ced765 100644 --- a/pkg/asset/rhcos/releaseextract.go +++ b/pkg/asset/rhcos/releaseextract.go @@ -270,7 +270,7 @@ func (r *releasePayload) getHashFromInstaller(architecture string) (bool, string ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) defer cancel() - st, err := rhcos.FetchCoreOSBuild(ctx, rhcos.DefaultOSImageStream) + st, err := rhcos.FetchCoreOSBuild(ctx, types.OSImageStreamRHCOS9) if err != nil { return false, "" } diff --git a/pkg/coreoscli/cmd.go b/pkg/coreoscli/cmd.go index d36aa1aa866..8a614bf3e4b 100644 --- a/pkg/coreoscli/cmd.go +++ b/pkg/coreoscli/cmd.go @@ -5,6 +5,8 @@ import ( "fmt" "os" + "github.com/openshift/installer/pkg/types/defaults" + "github.com/spf13/cobra" "github.com/openshift/installer/pkg/rhcos" @@ -13,11 +15,12 @@ import ( // printStreamJSON is the implementation of print-stream-json func printStreamJSON(cmd *cobra.Command, _ []string) error { - osImageStream := rhcos.DefaultOSImageStream streamFlag, err := cmd.Flags().GetString("stream") if err != nil { return err } + + osImageStream := rhcos.DefaultOSImageStream if streamFlag != "" { s := types.OSImageStream(streamFlag) valid := false @@ -31,7 +34,13 @@ func printStreamJSON(cmd *cobra.Command, _ []string) error { return fmt.Errorf("invalid value %q for --stream; must be one of %v", streamFlag, types.OSImageStreamValues) } osImageStream = s + } else { + // If no stream is given get it from the default FeatureSet for the build version + installConfig := types.InstallConfig{} + defaults.SetInstallConfigDefaults(&installConfig) + osImageStream = installConfig.OSImageStream } + streamData, err := rhcos.FetchRawCoreOSStream(context.Background(), osImageStream) if err != nil { return err diff --git a/pkg/destroy/bootstrap/bootstrap.go b/pkg/destroy/bootstrap/bootstrap.go index 953680ad395..676aab9bdad 100644 --- a/pkg/destroy/bootstrap/bootstrap.go +++ b/pkg/destroy/bootstrap/bootstrap.go @@ -69,9 +69,9 @@ func Destroy(ctx context.Context, dir string) (err error) { } } - featureSets, ok := types.FeatureSetsForProfile() - if !ok { - return fmt.Errorf("no feature sets for cluster profile %q", types.GetClusterProfileName()) + featureSets, err := types.FeatureSetsForProfile() + if err != nil { + return fmt.Errorf("no feature sets for cluster profile %q. %w", types.GetClusterProfileName(), err) } fg := featuregates.FeatureGateFromFeatureSets(featureSets, metadata.FeatureSet, metadata.CustomFeatureSet) diff --git a/pkg/rhcos/stream.go b/pkg/rhcos/stream.go index 16c8683cbf0..678112c36c2 100644 --- a/pkg/rhcos/stream.go +++ b/pkg/rhcos/stream.go @@ -8,14 +8,9 @@ import ( "github.com/openshift/installer/pkg/types" ) -const ( - // DefaultOSImageStream is the OS image stream used when the install-config - // does not specify one. - DefaultOSImageStream = types.OSImageStreamRHCOS9 - - payloadImageStreamTagRHCOS9 = "rhel-coreos" - payloadImageStreamTagRHCOS10 = "rhel-coreos-10" -) +// DefaultOSImageStream is the OS image stream used when the install-config +// does not specify one. +const DefaultOSImageStream = types.OSImageStreamRHCOS10 func getStreamFileName(stream types.OSImageStream) string { return fmt.Sprintf("coreos/coreos-%v.json", stream) @@ -24,12 +19,3 @@ func getStreamFileName(stream types.OSImageStream) string { func getMarketplaceStreamFileName(stream types.OSImageStream) string { return fmt.Sprintf("coreos/marketplace/coreos-%v.json", stream) } - -// GetPayloadImageStreamTag returns the payload image stream tag corresponding -// to the given OS image stream. -func GetPayloadImageStreamTag(stream types.OSImageStream) string { - if stream == types.OSImageStreamRHCOS9 { - return payloadImageStreamTagRHCOS9 - } - return payloadImageStreamTagRHCOS10 -} diff --git a/pkg/rhcos/stream_scos.go b/pkg/rhcos/stream_scos.go index 518aa0b1f5f..687eac51e3c 100644 --- a/pkg/rhcos/stream_scos.go +++ b/pkg/rhcos/stream_scos.go @@ -18,9 +18,3 @@ func getMarketplaceStreamFileName(_ types.OSImageStream) string { // functions will gracefully handle the missing file. return "coreos/marketplace/marketplace-scos.json" } - -// GetPayloadImageStreamTag returns the payload image stream tag corresponding -// to the given OS image stream. For SCOS, this always returns "stream-coreos". -func GetPayloadImageStreamTag(_ types.OSImageStream) string { - return "stream-coreos" -} diff --git a/pkg/types/defaults/installconfig.go b/pkg/types/defaults/installconfig.go index 6e88ba5aba7..c7c1be3f8a8 100644 --- a/pkg/types/defaults/installconfig.go +++ b/pkg/types/defaults/installconfig.go @@ -1,6 +1,7 @@ package defaults import ( + "github.com/openshift/api/features" operv1 "github.com/openshift/api/operator/v1" "github.com/openshift/installer/pkg/ipnet" "github.com/openshift/installer/pkg/rhcos" @@ -137,6 +138,11 @@ func SetInstallConfigDefaults(c *types.InstallConfig) { if c.OSImageStream == "" { c.OSImageStream = rhcos.DefaultOSImageStream + if !c.IsSCOS() && !c.Enabled(features.FeatureGateOSStreams) { + // Use RHEL 9 by default only if the FG is disabled + // OKD uses only 1 stream so this condition doesn't apply + c.OSImageStream = types.OSImageStreamRHCOS9 + } } if c.AdditionalTrustBundlePolicy == "" { diff --git a/pkg/types/defaults/machinepools.go b/pkg/types/defaults/machinepools.go index cf778e1e670..ad5475d98a0 100644 --- a/pkg/types/defaults/machinepools.go +++ b/pkg/types/defaults/machinepools.go @@ -10,7 +10,6 @@ import ( azuredefaults "github.com/openshift/installer/pkg/types/azure/defaults" "github.com/openshift/installer/pkg/types/gcp" gcpdefaults "github.com/openshift/installer/pkg/types/gcp/defaults" - "github.com/openshift/installer/pkg/version" ) // SetMachinePoolDefaults sets the defaults for the machine pool. @@ -26,7 +25,7 @@ func SetMachinePoolDefaults(p *types.MachinePool, platform *types.Platform) { p.Hyperthreading = types.HyperthreadingEnabled } if p.Architecture == "" { - p.Architecture = version.DefaultArch() + p.Architecture = types.DefaultArch() } if p.Fencing != nil { diff --git a/pkg/types/installconfig.go b/pkg/types/installconfig.go index fcfda23cc9e..faace481566 100644 --- a/pkg/types/installconfig.go +++ b/pkg/types/installconfig.go @@ -623,9 +623,9 @@ func (c *InstallConfig) EnabledFeatureGates() featuregates.FeatureGate { customFS = featuregates.GenerateCustomFeatures(c.FeatureGates) } - featureSets, ok := FeatureSetsForProfile() - if !ok { - logrus.Warnf("no feature sets for cluster profile %q", GetClusterProfileName()) + featureSets, err := FeatureSetsForProfile() + if err != nil { + logrus.Warnf("no feature sets for cluster profile %q. %v", GetClusterProfileName(), err) } fg := featuregates.FeatureGateFromFeatureSets(featureSets, c.FeatureSet, customFS) diff --git a/pkg/types/utils.go b/pkg/types/utils.go index 99c8014fb15..fa03d42a284 100644 --- a/pkg/types/utils.go +++ b/pkg/types/utils.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/openshift/installer/pkg/version" + "github.com/sirupsen/logrus" capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" @@ -43,21 +45,24 @@ func MachineNetworksToCIDRs(nets []MachineNetworkEntry) []configv1.CIDR { return res } -// openshiftMajorVersion is the major version of OpenShift that this installer targets. -// This is used when looking up feature sets from the API. -const openshiftMajorVersion uint64 = 4 - // FeatureSetsForProfile returns the feature sets for the current cluster profile // and OpenShift major version. -func FeatureSetsForProfile() (map[configv1.FeatureSet]*features.FeatureGateEnabledDisabled, bool) { +func FeatureSetsForProfile() (map[configv1.FeatureSet]*features.FeatureGateEnabledDisabled, error) { clusterProfile := GetClusterProfileName() allSets := features.AllFeatureSets() - versionSets, ok := allSets[openshiftMajorVersion] + versionInfo, err := version.GetVersionInfo() + if err != nil { + return nil, fmt.Errorf("unable to determine version information to calculate FeatureSets: %w", err) + } + versionSets, ok := allSets[uint64(versionInfo.Major)] if !ok { - return nil, false + return nil, fmt.Errorf("no FeatureSet available for version %d", versionInfo.Major) } profileSets, ok := versionSets[clusterProfile] - return profileSets, ok + if !ok { + return nil, fmt.Errorf("no FeatureSet available for %s cluster profile", clusterProfile) + } + return profileSets, nil } // GetClusterProfileName utility method to retrieve the cluster profile setting. This is used @@ -103,3 +108,8 @@ func (c *InstallConfig) CreateAzureIdentity() bool { return defaultNeedsID && (computeNeedsID || cpNeedsID) } + +// DefaultArch returns the default release architecture +func DefaultArch() Architecture { + return Architecture(version.DefaultArch()) +} diff --git a/pkg/types/validation/installconfig.go b/pkg/types/validation/installconfig.go index d6c088ee596..d5f0066ffee 100644 --- a/pkg/types/validation/installconfig.go +++ b/pkg/types/validation/installconfig.go @@ -1574,9 +1574,9 @@ func validateAdditionalCABundlePolicy(c *types.InstallConfig) error { func ValidateFeatureSet(c *types.InstallConfig) field.ErrorList { allErrs := field.ErrorList{} - featureSets, ok := types.FeatureSetsForProfile() - if !ok { - logrus.Warnf("no feature sets for cluster profile %q", types.GetClusterProfileName()) + featureSets, err := types.FeatureSetsForProfile() + if err != nil { + logrus.Warnf("no feature sets for cluster profile %q. %s", types.GetClusterProfileName(), err) } if _, ok := featureSets[c.FeatureSet]; c.FeatureSet != configv1.CustomNoUpgrade && !ok { sortedFeatureSets := func() []string { @@ -1679,7 +1679,7 @@ func validateGatedFeatures(c *types.InstallConfig) field.ErrorList { func validateReleaseArchitecture(controlPlanePool *types.MachinePool, computePool []types.MachinePool, releaseArch types.Architecture) field.ErrorList { allErrs := field.ErrorList{} - clusterArch := version.DefaultArch() + clusterArch := types.DefaultArch() if controlPlanePool != nil && controlPlanePool.Architecture != "" { clusterArch = controlPlanePool.Architecture } diff --git a/pkg/version/version.go b/pkg/version/version.go index 730e553d99d..b4f296ab4a2 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -4,13 +4,51 @@ package version import ( "fmt" "os" + "strconv" "strings" "github.com/sirupsen/logrus" - - "github.com/openshift/installer/pkg/types" ) +// VersionInfo represents a parsed semantic version. +type VersionInfo struct { + Major int + Minor int + Patch int +} + +// GetVersionInfo returns the build version parsed as a VersionInfo. +func GetVersionInfo() (VersionInfo, error) { + s, err := Version() + if err != nil { + return VersionInfo{}, err + } + return parseVersionInfo(s) +} + +func parseVersionInfo(s string) (VersionInfo, error) { + if idx := strings.Index(s, "-"); idx != -1 { + s = s[:idx] + } + parts := strings.Split(s, ".") + if len(parts) == 0 { + return VersionInfo{}, fmt.Errorf("invalid version %q", s) + } + var v VersionInfo + major, err := strconv.Atoi(parts[0]) + if err != nil { + return VersionInfo{}, fmt.Errorf("invalid version %q", s) + } + v.Major = major + if len(parts) > 1 { + v.Minor, _ = strconv.Atoi(parts[1]) + } + if len(parts) > 2 { + v.Patch, _ = strconv.Atoi(parts[2]) + } + return v, nil +} + // This file handles correctly identifying the default release version, which is expected to be // replaced in the binary post-compile by the release name extracted from a payload. The expected modification is: // @@ -65,7 +103,7 @@ func String() (string, error) { // Version returns the installer/release version. func Version() (string, error) { if strings.HasPrefix(defaultVersionPadded, defaultVersionPrefix) { - return Raw, nil + return removeGoVersionPrefix(Raw), nil } nullTerminator := strings.IndexByte(defaultVersionPadded, '\x00') if nullTerminator == -1 { @@ -125,7 +163,20 @@ func cleanArch(releaseArchitecture string) string { return strings.ReplaceAll(releaseArchitecture, "linux/", "") } -// DefaultArch returns the default release architecture -func DefaultArch() types.Architecture { - return types.Architecture(defaultArch) +// removeGoVersionPrefix converts a Go module version tag (e.g. "v1.4.22") +// into the corresponding OCP version (e.g. "4.22"). +func removeGoVersionPrefix(version string) string { + if strings.HasPrefix(version, "v") { + version = strings.TrimPrefix(version, "v") + parts := strings.SplitN(version, ".", 2) + if len(parts) > 1 { + version = parts[1] + } + } + return version +} + +// DefaultArch returns the default release architecture embedded in the binary +func DefaultArch() string { + return defaultArch }