Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile.rhel
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.24-openshift-4.21 AS builder
WORKDIR /go/src/github.com/openshift/cluster-version-operator
COPY . .
RUN hack/build-go.sh; \
ARG TAGS=""
RUN TAGS="${TAGS}" hack/build-go.sh; \
mkdir -p /tmp/build; \
cp _output/linux/$(go env GOARCH)/cluster-version-operator _output/linux/$(go env GOARCH)/cluster-version-operator-tests.gz /tmp/build/

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ require (
github.com/onsi/ginkgo/v2 v2.21.0
github.com/onsi/gomega v1.35.1
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45
github.com/openshift/api v0.0.0-20251127005036-0e3c378fdedc
github.com/openshift/client-go v0.0.0-20251201171210-333716c1124a
github.com/openshift/api v0.0.0-20251214014457-bfa868a22401
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c
github.com/openshift/library-go v0.0.0-20251120164824-14a789e09884
github.com/operator-framework/api v0.17.1
github.com/operator-framework/operator-lifecycle-manager v0.22.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45 h1:hXpbYtP3iTh8oy/RKwKkcMziwchY3fIk95ciczf7cOA=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift/api v0.0.0-20251127005036-0e3c378fdedc h1:p83VYAk7mlqYZrMaKuu2bBNNLUKBUSCa6YzjPDqbOlk=
github.com/openshift/api v0.0.0-20251127005036-0e3c378fdedc/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/client-go v0.0.0-20251201171210-333716c1124a h1:iJYjd+rxyjMa3Sk6Vg55secJ4yMrabr/ulnTiy+vDH0=
github.com/openshift/client-go v0.0.0-20251201171210-333716c1124a/go.mod h1:WD7m8ADeqiAKTHWx/mBoE/1MFMtnt9MYTyBOnf0L3LI=
github.com/openshift/api v0.0.0-20251214014457-bfa868a22401 h1:goMf6pBtRFSQaVElFk6K+GIAqnv7O84p7PJHH6pDz/E=
github.com/openshift/api v0.0.0-20251214014457-bfa868a22401/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c h1:TBE0Gl+oCo/SNEhLKZQNNH/SWHXrpGyhAw7P0lAqdHg=
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c/go.mod h1:IsynOWZAfdH+BgWimcFQRtI41Id9sgdhsCEjIk8ACLw=
github.com/openshift/library-go v0.0.0-20251120164824-14a789e09884 h1:6512TMT14gnXQ4vyshzAQGjkctU0PO9G+y0tcBjw6Vk=
github.com/openshift/library-go v0.0.0-20251120164824-14a789e09884/go.mod h1:ErDfiIrPHH+menTP/B4LKd0nxFDdvCbTamAc6SWMIh8=
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241205171354-8006f302fd12 h1:AKx/w1qpS8We43bsRgf8Nll3CGlDHpr/WAXvuedTNZI=
Expand Down
7 changes: 6 additions & 1 deletion hack/build-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ LDFLAGS_TEST_EXTENSION+=" -X '${OPENSHIFT_TESTS_EXTENSION_MODULE}/pkg/version.Bu
LDFLAGS_TEST_EXTENSION+=" -X '${OPENSHIFT_TESTS_EXTENSION_MODULE}/pkg/version.GitTreeState=${GIT_TREE_STATE}'"

echo "Building ${REPO} cluster-version-operator-tests binary (${VERSION_OVERRIDE})"
TAGS_FLAG=""
if [ -n "${TAGS:-}" ]; then
TAGS_FLAG="-tags=${TAGS}"
fi
GO_COMPLIANCE_POLICY="exempt_all" CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} \
go build \
${GOFLAGS} \
${TAGS_FLAG} \
-ldflags "${LDFLAGS_TEST_EXTENSION}" \
-o "${BIN_PATH}/cluster-version-operator-tests" \
"${REPO}/cmd/cluster-version-operator-tests/..."
Expand All @@ -35,4 +40,4 @@ gzip --keep --force "${BIN_PATH}/cluster-version-operator-tests"
# Build the cluster-version-operator binary
GLDFLAGS+="-X ${REPO}/pkg/version.Raw=${VERSION_OVERRIDE}"
echo "Building ${REPO} cluster-version-operator binary (${VERSION_OVERRIDE})"
GOOS=${GOOS} GOARCH=${GOARCH} go build ${GOFLAGS} -ldflags "${GLDFLAGS}" -o ${BIN_PATH}/cluster-version-operator ${REPO}/cmd/cluster-version-operator/...
GOOS=${GOOS} GOARCH=${GOARCH} go build ${GOFLAGS} ${TAGS_FLAG} -ldflags "${GLDFLAGS}" -o ${BIN_PATH}/cluster-version-operator ${REPO}/cmd/cluster-version-operator/...
4 changes: 2 additions & 2 deletions pkg/payload/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ func renderDir(renderConfig manifestRenderConfig, idir, odir string, requiredFea
if skipFiles.Has(file.Name()) {
continue
}
if strings.Contains(file.Name(), "CustomNoUpgrade") || strings.Contains(file.Name(), "TechPreviewNoUpgrade") || strings.Contains(file.Name(), "DevPreviewNoUpgrade") {
// CustomNoUpgrade, TechPreviewNoUpgrade and DevPreviewNoUpgrade may add features to manifests like the ClusterVersion CRD,
if strings.Contains(file.Name(), "CustomNoUpgrade") || strings.Contains(file.Name(), "TechPreviewNoUpgrade") || strings.Contains(file.Name(), "DevPreviewNoUpgrade") || strings.Contains(file.Name(), "OKD") {
// CustomNoUpgrade, TechPreviewNoUpgrade, DevPreviewNoUpgrade and OKD may add features to manifests like the ClusterVersion CRD,
// but we do not need those features during bootstrap-render time. In those clusters, the production
// CVO will be along shortly to update the manifests and deliver the gated features.
// fixme: now that we have requiredFeatureSet, use it to do Manifest.Include() filtering here instead of making filename assumptions
Expand Down
50 changes: 43 additions & 7 deletions pkg/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
coreinformers "k8s.io/client-go/informers"
Expand Down Expand Up @@ -46,6 +47,7 @@ import (
"github.com/openshift/cluster-version-operator/pkg/featuregates"
"github.com/openshift/cluster-version-operator/pkg/internal"
"github.com/openshift/cluster-version-operator/pkg/payload"
"github.com/openshift/cluster-version-operator/pkg/version"
)

const (
Expand Down Expand Up @@ -188,7 +190,8 @@ func (o *Options) Run(ctx context.Context) error {
}

clusterVersionConfigInformerFactory, configInformerFactory := o.prepareConfigInformerFactories(cb)
startingFeatureSet, startingCvoGates, err := o.processInitialFeatureGate(ctx, configInformerFactory)
configClient := cb.ClientOrDie("feature-gate-migration")
startingFeatureSet, startingCvoGates, err := o.processInitialFeatureGate(ctx, configInformerFactory, configClient)
if err != nil {
return fmt.Errorf("error processing feature gates: %w", err)
}
Expand Down Expand Up @@ -242,7 +245,7 @@ func (o *Options) getOpenShiftVersion() string {
return releaseMetadata.Version
}

func (o *Options) processInitialFeatureGate(ctx context.Context, configInformerFactory configinformers.SharedInformerFactory) (configv1.FeatureSet, featuregates.CvoGates, error) {
func (o *Options) processInitialFeatureGate(ctx context.Context, configInformerFactory configinformers.SharedInformerFactory, configClient clientset.Interface) (configv1.FeatureSet, featuregates.CvoGates, error) {
var startingFeatureSet configv1.FeatureSet
var cvoGates featuregates.CvoGates

Expand All @@ -266,19 +269,52 @@ func (o *Options) processInitialFeatureGate(ctx context.Context, configInformerF
gate, err := featureGates.Get("cluster")
switch {
case apierrors.IsNotFound(err):
// if we have no featuregates, then the cluster is using the default featureset, which is "".
// This excludes everything that could possibly depend on a different feature set.
startingFeatureSet = ""
klog.Infof("FeatureGate not found in cluster, will assume default feature set %q at startup", startingFeatureSet)
// if we have no featuregates and this is an OKD build, then the cluster is using OKD featureset.
// The FeatureGate resource will be created by the installer.
if version.IsSCOS() {
startingFeatureSet = configv1.FeatureSet(configv1.OKD)
klog.Infof("FeatureGate not found in cluster, will assume OKD feature set %q at startup", startingFeatureSet)
} else {
klog.Infof("FeatureGate not found in cluster, using default feature set at startup")
}
case err != nil:
// This should not happen because featureGates is backed by the informer cache which successfully synced earlier
klog.Errorf("Failed to get FeatureGate from cluster: %v", err)
return startingFeatureSet, cvoGates, fmt.Errorf("failed to get FeatureGate from informer cache: %w", err)
default:
clusterFeatureGate = gate
startingFeatureSet = gate.Spec.FeatureSet
cvoGates = featuregates.CvoGatesFromFeatureGate(clusterFeatureGate, cvoOpenShiftVersion)
klog.Infof("FeatureGate found in cluster, using its feature set %q at startup", startingFeatureSet)

// Migrate from Default ("") to OKD for existing clusters during upgrade (only for OKD builds)
if version.IsSCOS() && (startingFeatureSet == "" || startingFeatureSet == configv1.Default) {
klog.Infof("Detected Default feature set, migrating to OKD feature set")

// Patch the FeatureGate to change from Default to OKD
patchData := []byte(fmt.Sprintf(`{"spec":{"featureSet":"%s"}}`, configv1.OKD))
patchedGate, patchErr := configClient.ConfigV1().FeatureGates().Patch(
ctx,
"cluster",
types.MergePatchType,
patchData,
metav1.PatchOptions{},
)
if patchErr != nil {
klog.Errorf("Failed to migrate FeatureGate from Default to OKD: %v", patchErr)
klog.Warningf("Continuing with Default feature set; migration will be retried on next restart")
// Continue with Default - don't fail startup
} else {
klog.Infof("Successfully migrated FeatureGate from Default to OKD")
startingFeatureSet = configv1.FeatureSet(configv1.OKD)
clusterFeatureGate = patchedGate

// Note: The FeatureChangeStopper will detect this change and trigger a restart
// This is expected and ensures CVO starts cleanly with the new feature set
klog.Infof("CVO will restart to apply OKD feature set changes")
}
}
// Compute CVO gates from the feature gate (potentially migrated)
cvoGates = featuregates.CvoGatesFromFeatureGate(clusterFeatureGate, cvoOpenShiftVersion)
}

if cvoGates.UnknownVersion() {
Expand Down
9 changes: 6 additions & 3 deletions pkg/start/start_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ func TestIntegrationCVO_initializeAndUpgrade(t *testing.T) {
}

clusterVersionConfigInformerFactory, configInformerFactory := options.prepareConfigInformerFactories(cb)
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory)
configClient := cb.ClientOrDie("feature-gate-migration")
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory, configClient)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -333,7 +334,8 @@ func TestIntegrationCVO_gracefulStepDown(t *testing.T) {
}

clusterVersionConfigInformerFactory, configInformerFactory := options.prepareConfigInformerFactories(cb)
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory)
configClient := cb.ClientOrDie("feature-gate-migration")
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory, configClient)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -536,7 +538,8 @@ metadata:
}

clusterVersionConfigInformerFactory, configInformerFactory := options.prepareConfigInformerFactories(cb)
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory)
configClient := cb.ClientOrDie("feature-gate-migration")
featureset, gates, err := options.processInitialFeatureGate(context.Background(), configInformerFactory, configClient)
if err != nil {
t.Fatal(err)
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/version/scos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build scos

package version

func init() {
SCOS = true
}
10 changes: 10 additions & 0 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@ var (

// String is the human-friendly representation of the version.
String = fmt.Sprintf("ClusterVersionOperator %s", Raw)

// SCOS is a setting to enable CentOS Stream CoreOS-only modifications.
// This is set via the scos build tag.
SCOS = false
)

// IsSCOS returns true if CentOS Stream CoreOS-only modifications are enabled.
// This is enabled via the scos build tag for OKD builds.
func IsSCOS() bool {
return SCOS
}
2 changes: 0 additions & 2 deletions vendor/github.com/openshift/api/config/v1/register.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions vendor/github.com/openshift/api/config/v1/types_feature.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading