diff --git a/go.mod b/go.mod index eaf456d0d2..c06eb907ba 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,11 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/ghodss/yaml v1.0.0 github.com/google/go-cmp v0.6.0 - github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f + github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2 github.com/openshift/build-machinery-go v0.0.0-20241031155326-6ae126a9cb72 github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f - github.com/openshift/library-go v0.0.0-20241106000323-9fcf3125a28e - github.com/openshift/multi-operator-manager v0.0.0-20241101153049-fcf403de1051 + github.com/openshift/library-go v0.0.0-20241126120118-cc54dd38ae04 + github.com/openshift/multi-operator-manager v0.0.0-20241121231342-ecea9d7ffa35 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 go.etcd.io/etcd/client/v3 v3.5.14 diff --git a/go.sum b/go.sum index e26aa2124e..ff9e953290 100644 --- a/go.sum +++ b/go.sum @@ -148,16 +148,16 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f h1:ya1OmyZm3LIIxI3U9VE9Nyx3ehCHgBwxyFUPflYPWls= -github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo= +github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2 h1:CguNy+2KzhJ3a3i7e4Bgm/ByfQpSSSPYmF9NLZskoUs= +github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo= github.com/openshift/build-machinery-go v0.0.0-20241031155326-6ae126a9cb72 h1:kMM+Ea3YFrcoYS76RhhBA7uELy97JM0gwqnyoy7fxco= github.com/openshift/build-machinery-go v0.0.0-20241031155326-6ae126a9cb72/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f h1:FRc0bVNWprihWS0GqQWzb3dY4dkCwpOP3mDw5NwSoR4= github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f/go.mod h1:KiZi2mJRH1TOJ3FtBDYS6YvUL30s/iIXaGSUrSa36mo= -github.com/openshift/library-go v0.0.0-20241106000323-9fcf3125a28e h1:ZPAUe9p5nfbzJzb23s+rdFqDrl3U58hC4Y0merEkoSE= -github.com/openshift/library-go v0.0.0-20241106000323-9fcf3125a28e/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0= -github.com/openshift/multi-operator-manager v0.0.0-20241101153049-fcf403de1051 h1:2Rsvg5O5xvQfLAxsiOwlAEJepNtLPTLXIFHB46RS3Mo= -github.com/openshift/multi-operator-manager v0.0.0-20241101153049-fcf403de1051/go.mod h1:UBAANHcEhysEeyhtIoLZS5dFYOjjZrv9lUgtHt3cFLk= +github.com/openshift/library-go v0.0.0-20241126120118-cc54dd38ae04 h1:G/WKwNS4LDxxYm0bm3BFHV/LQoSfq48aYa76lXuhFw8= +github.com/openshift/library-go v0.0.0-20241126120118-cc54dd38ae04/go.mod h1:l/3SegTa9x+ry2J213bh7+DBofXOOvdrqU4JC9ktJa0= +github.com/openshift/multi-operator-manager v0.0.0-20241121231342-ecea9d7ffa35 h1:UdM0DernMOKB5FwiCzyRx/viWeMowq3TNDbgP5zwpVk= +github.com/openshift/multi-operator-manager v0.0.0-20241121231342-ecea9d7ffa35/go.mod h1:J/kijVY/wCcr2yVGe23wTW4wRNQrsTngWUQOFd2sQsM= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/cmd/operator/cmd.go b/pkg/cmd/operator/cmd.go index b3158dfd89..dc61ea7ad0 100644 --- a/pkg/cmd/operator/cmd.go +++ b/pkg/cmd/operator/cmd.go @@ -3,6 +3,8 @@ package operator import ( "github.com/spf13/cobra" + "k8s.io/utils/clock" + "github.com/openshift/cluster-authentication-operator/pkg/operator" "github.com/openshift/cluster-authentication-operator/pkg/version" "github.com/openshift/library-go/pkg/controller/controllercmd" @@ -11,7 +13,7 @@ import ( const componentName = "cluster-authentication-operator" func NewOperator() *cobra.Command { - cmd := controllercmd.NewControllerCommandConfig(componentName, version.Get(), operator.RunOperator).NewCommand() + cmd := controllercmd.NewControllerCommandConfig(componentName, version.Get(), operator.RunOperator, clock.RealClock{}).NewCommand() cmd.Use = "operator" cmd.Short = "Start the Authentication Operator" return cmd diff --git a/pkg/controllers/configobservation/console/observe_consoleurl_test.go b/pkg/controllers/configobservation/console/observe_consoleurl_test.go index 083788b0cf..8321ad934a 100644 --- a/pkg/controllers/configobservation/console/observe_consoleurl_test.go +++ b/pkg/controllers/configobservation/console/observe_consoleurl_test.go @@ -4,9 +4,11 @@ import ( "reflect" "strings" "testing" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -111,7 +113,7 @@ func TestObserveConsoleURL(t *testing.T) { ClusterVersionLister: configlistersv1.NewClusterVersionLister(clusterVersionIndexer), } - eventRecorder := events.NewInMemoryRecorder(tt.name) + eventRecorder := events.NewInMemoryRecorder(tt.name, clocktesting.NewFakePassiveClock(time.Now())) gotConfig, errs := ObserveConsoleURL(listers, eventRecorder, tt.existingConfig) if !reflect.DeepEqual(gotConfig, tt.expectedConfig) { t.Errorf("ObserveConsoleURL() gotConfig = %v, want %v", gotConfig, tt.expectedConfig) diff --git a/pkg/controllers/configobservation/infrastructure/observe_apiserverurl_test.go b/pkg/controllers/configobservation/infrastructure/observe_apiserverurl_test.go index c0d7d166e4..06a4a07272 100644 --- a/pkg/controllers/configobservation/infrastructure/observe_apiserverurl_test.go +++ b/pkg/controllers/configobservation/infrastructure/observe_apiserverurl_test.go @@ -4,9 +4,11 @@ import ( "reflect" "strings" "testing" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -73,7 +75,7 @@ func TestObserveAPIServerURL(t *testing.T) { InfrastructureLister: configlistersv1.NewInfrastructureLister(indexer), } - eventRecorder := events.NewInMemoryRecorder(tt.name) + eventRecorder := events.NewInMemoryRecorder(tt.name, clocktesting.NewFakePassiveClock(time.Now())) gotConfig, errs := ObserveAPIServerURL(listers, eventRecorder, tt.existingConfig) if !reflect.DeepEqual(gotConfig, tt.expectedConfig) { t.Errorf("ObserveAPIServerURL() gotConfig = %v, want %v", gotConfig, tt.expectedConfig) diff --git a/pkg/controllers/configobservation/oauth/observe_audit_test.go b/pkg/controllers/configobservation/oauth/observe_audit_test.go index c00d5d70bc..b42bc01fa5 100644 --- a/pkg/controllers/configobservation/oauth/observe_audit_test.go +++ b/pkg/controllers/configobservation/oauth/observe_audit_test.go @@ -2,12 +2,14 @@ package oauth_test import ( "testing" + "time" "github.com/google/go-cmp/cmp" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -120,7 +122,7 @@ func TestAuditProfile(t *testing.T) { APIServerLister_: configlistersv1.NewAPIServerLister(indexer), } - have, errs := oauth.ObserveAudit(listers, events.NewInMemoryRecorder(t.Name()), tt.previouslyObservedConfig) + have, errs := oauth.ObserveAudit(listers, events.NewInMemoryRecorder(t.Name(), clocktesting.NewFakePassiveClock(time.Now())), tt.previouslyObservedConfig) if len(errs) > 0 { t.Errorf("Expected 0 errors, have %v.", len(errs)) } diff --git a/pkg/controllers/configobservation/oauth/observe_idps_test.go b/pkg/controllers/configobservation/oauth/observe_idps_test.go index 95b163385b..152925aa75 100644 --- a/pkg/controllers/configobservation/oauth/observe_idps_test.go +++ b/pkg/controllers/configobservation/oauth/observe_idps_test.go @@ -3,6 +3,7 @@ package oauth import ( "fmt" "testing" + "time" "github.com/google/go-cmp/cmp" @@ -11,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corelistersv1 "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -199,7 +201,7 @@ func TestObserveIdentityProviders(t *testing.T) { OAuthLister_: configlistersv1.NewOAuthLister(indexer), ResourceSync: &mockResourceSyncer{t: t, synced: syncerData}, } - eventsRecorder := events.NewInMemoryRecorder(t.Name()) + eventsRecorder := events.NewInMemoryRecorder(t.Name(), clocktesting.NewFakePassiveClock(time.Now())) got, errs := ObserveIdentityProviders(listers, eventsRecorder, tt.previouslyObservedConfig) diff --git a/pkg/controllers/configobservation/oauth/observe_templates_test.go b/pkg/controllers/configobservation/oauth/observe_templates_test.go index 1bf15911dc..a83fb1ef14 100644 --- a/pkg/controllers/configobservation/oauth/observe_templates_test.go +++ b/pkg/controllers/configobservation/oauth/observe_templates_test.go @@ -2,6 +2,7 @@ package oauth import ( "testing" + "time" "github.com/google/go-cmp/cmp" @@ -9,6 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corelistersv1 "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -88,7 +90,7 @@ func TestObserveTemplates(t *testing.T) { ConfigMapLister: corelistersv1.NewConfigMapLister(indexer), ResourceSync: &mockResourceSyncer{t: t, synced: syncerData}, } - got, errs := ObserveTemplates(listers, events.NewInMemoryRecorder(t.Name()), tt.previouslyObservedConfig) + got, errs := ObserveTemplates(listers, events.NewInMemoryRecorder(t.Name(), clocktesting.NewFakePassiveClock(time.Now())), tt.previouslyObservedConfig) if len(errs) > 0 { t.Errorf("Expected 0 errors, got %v.", len(errs)) } diff --git a/pkg/controllers/configobservation/oauth/observe_tokenconfig_test.go b/pkg/controllers/configobservation/oauth/observe_tokenconfig_test.go index f4a1edc011..6ce8f84652 100644 --- a/pkg/controllers/configobservation/oauth/observe_tokenconfig_test.go +++ b/pkg/controllers/configobservation/oauth/observe_tokenconfig_test.go @@ -2,12 +2,14 @@ package oauth import ( "testing" + "time" "github.com/google/go-cmp/cmp" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -119,7 +121,7 @@ func TestObserveTokenConfig(t *testing.T) { listers := configobservation.Listers{ OAuthLister_: configlistersv1.NewOAuthLister(indexer), } - got, errs := ObserveTokenConfig(listers, events.NewInMemoryRecorder(t.Name()), tt.previouslyObservedConfig) + got, errs := ObserveTokenConfig(listers, events.NewInMemoryRecorder(t.Name(), clocktesting.NewFakePassiveClock(time.Now())), tt.previouslyObservedConfig) if len(errs) > 0 { t.Errorf("Expected 0 errors, got %v.", len(errs)) } diff --git a/pkg/controllers/configobservation/routersecret/observe_router_secret_test.go b/pkg/controllers/configobservation/routersecret/observe_router_secret_test.go index 1c24e8db07..358f80ff6d 100644 --- a/pkg/controllers/configobservation/routersecret/observe_router_secret_test.go +++ b/pkg/controllers/configobservation/routersecret/observe_router_secret_test.go @@ -3,6 +3,7 @@ package routersecret import ( "reflect" "testing" + "time" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -10,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" corev1listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -180,7 +182,7 @@ func TestObserveRouterSecret(t *testing.T) { IngressLister: configlistersv1.NewIngressLister(indexer), } - eventRecorder := events.NewInMemoryRecorder(tt.name) + eventRecorder := events.NewInMemoryRecorder(tt.name, clocktesting.NewFakePassiveClock(time.Now())) gotConfig, errs := ObserveRouterSecret(listers, eventRecorder, tt.existingConfig) if !reflect.DeepEqual(gotConfig, tt.expectedConfig) { t.Errorf("ObserveRouterSecret() gotConfig = %v, want %v", gotConfig, tt.expectedConfig) diff --git a/pkg/controllers/routercerts/controller_test.go b/pkg/controllers/routercerts/controller_test.go index 54aeb4abe5..999e529658 100644 --- a/pkg/controllers/routercerts/controller_test.go +++ b/pkg/controllers/routercerts/controller_test.go @@ -22,6 +22,7 @@ import ( "k8s.io/client-go/kubernetes/fake" corev1listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" operatorv1 "github.com/openshift/api/operator/v1" @@ -249,7 +250,7 @@ func TestValidateRouterCertificates(t *testing.T) { systemCertPool: tc.systemCertPool, secretsClient: secretsClient.CoreV1(), } - err = controller.sync(context.TODO(), factory.NewSyncContext("testctx", events.NewInMemoryRecorder("test-recorder"))) + err = controller.sync(context.TODO(), factory.NewSyncContext("testctx", events.NewInMemoryRecorder("test-recorder", clocktesting.NewFakePassiveClock(time.Now())))) require.NoError(t, err) _, s, _, _ := operatorClient.GetOperatorState() require.Len(t, s.Conditions, 1) diff --git a/pkg/libs/endpointaccessible/endpoint_accessible_controller_test.go b/pkg/libs/endpointaccessible/endpoint_accessible_controller_test.go index 342e2ee15e..a4e3e0632d 100644 --- a/pkg/libs/endpointaccessible/endpoint_accessible_controller_test.go +++ b/pkg/libs/endpointaccessible/endpoint_accessible_controller_test.go @@ -4,6 +4,9 @@ import ( "context" "fmt" "testing" + "time" + + clocktesting "k8s.io/utils/clock/testing" operatorv1 "github.com/openshift/api/operator/v1" "github.com/openshift/library-go/pkg/operator/v1helpers" @@ -52,7 +55,7 @@ func Test_endpointAccessibleController_sync(t *testing.T) { operatorClient: v1helpers.NewFakeOperatorClient(&operatorv1.OperatorSpec{}, &operatorv1.OperatorStatus{}, nil), endpointListFn: tt.endpointListFn, } - if err := c.sync(context.Background(), factory.NewSyncContext(tt.name, events.NewInMemoryRecorder(tt.name))); (err != nil) != tt.wantErr { + if err := c.sync(context.Background(), factory.NewSyncContext(tt.name, events.NewInMemoryRecorder(tt.name, clocktesting.NewFakePassiveClock(time.Now())))); (err != nil) != tt.wantErr { t.Errorf("sync() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/pkg/operator/configobservation/authentication/apiaudiences_test.go b/pkg/operator/configobservation/authentication/apiaudiences_test.go index a435aa7db8..cf99fbc857 100644 --- a/pkg/operator/configobservation/authentication/apiaudiences_test.go +++ b/pkg/operator/configobservation/authentication/apiaudiences_test.go @@ -2,11 +2,13 @@ package auth import ( "testing" + "time" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -82,7 +84,7 @@ func TestObservedConfig(t *testing.T) { require.NoError(t, err) } - testRecorder := events.NewInMemoryRecorder("APIAudiencesTest") + testRecorder := events.NewInMemoryRecorder("APIAudiencesTest", clocktesting.NewFakePassiveClock(time.Now())) listers := configobservation.Listers{ AuthConfigLister_: configlistersv1.NewAuthenticationLister(indexer), } diff --git a/pkg/operator/configobservation/oauth/inactivity_timeout_test.go b/pkg/operator/configobservation/oauth/inactivity_timeout_test.go index 7fe3a977cc..5cf2e15e10 100644 --- a/pkg/operator/configobservation/oauth/inactivity_timeout_test.go +++ b/pkg/operator/configobservation/oauth/inactivity_timeout_test.go @@ -10,6 +10,7 @@ import ( "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" + clocktesting "k8s.io/utils/clock/testing" configv1 "github.com/openshift/api/config/v1" configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -181,7 +182,7 @@ func TestObserveAccessTokenInactivityTimeout(t *testing.T) { lister := testLister{lister: configlistersv1.NewOAuthLister(indexer)} - got, errs := ObserveAccessTokenInactivityTimeout(lister, events.NewInMemoryRecorder(t.Name()), tt.previouslyObservedConfig) + got, errs := ObserveAccessTokenInactivityTimeout(lister, events.NewInMemoryRecorder(t.Name(), clocktesting.NewFakePassiveClock(time.Now())), tt.previouslyObservedConfig) if len(errs) != len(tt.errors) { t.Errorf("Expected %d errors, got %d.", len(tt.errors), errs) } @@ -197,7 +198,7 @@ func TestObserveAccessTokenInactivityTimeout(t *testing.T) { }, } - got, errs := ObserveAccessTokenInactivityTimeout(invalidLister{}, events.NewInMemoryRecorder("fakeRecorder"), existingConfig) + got, errs := ObserveAccessTokenInactivityTimeout(invalidLister{}, events.NewInMemoryRecorder("fakeRecorder", clocktesting.NewFakePassiveClock(time.Now())), existingConfig) // There must be only one kind of error asserting the lister type. if len(errs) != 1 { diff --git a/pkg/operator/replacement_starter.go b/pkg/operator/replacement_starter.go index b516c53c11..55f7539e3f 100644 --- a/pkg/operator/replacement_starter.go +++ b/pkg/operator/replacement_starter.go @@ -39,7 +39,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" - "k8s.io/utils/clock" ) type authenticationOperatorInput struct { @@ -118,7 +117,7 @@ func CreateOperatorInputFromMOM(ctx context.Context, momInput libraryapplyconfig Kind: "Deployment", Namespace: "openshift-authentication-operator", Name: "authentication-operator", - }) + }, momInput.Clock) return &authenticationOperatorInput{ kubeClient: kubeClient, @@ -167,7 +166,7 @@ func CreateControllerInputFromControllerContext(ctx context.Context, controllerC } authenticationOperatorClient, dynamicInformers, err := genericoperatorclient.NewClusterScopedOperatorClient( - clock.RealClock{}, + controllerContext.Clock, controllerContext.KubeConfig, operatorv1.GroupVersion.WithResource("authentications"), operatorv1.GroupVersion.WithKind("Authentication"), @@ -187,6 +186,7 @@ func CreateControllerInputFromControllerContext(ctx context.Context, controllerC Namespace: "openshift-authentication-operator", Name: "authentication-operator", }, + controllerContext.Clock, ) return &authenticationOperatorInput{ diff --git a/pkg/operator/workload/sync_openshift_oauth_apiserver_test.go b/pkg/operator/workload/sync_openshift_oauth_apiserver_test.go index 8c9082f598..715d45068e 100644 --- a/pkg/operator/workload/sync_openshift_oauth_apiserver_test.go +++ b/pkg/operator/workload/sync_openshift_oauth_apiserver_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "testing" + "time" "github.com/google/go-cmp/cmp" @@ -19,6 +20,7 @@ import ( "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" clientgotesting "k8s.io/client-go/testing" + clocktesting "k8s.io/utils/clock/testing" ) var codec = scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) @@ -136,7 +138,7 @@ func TestSyncOAuthAPIServerDeployment(t *testing.T) { for _, scenario := range scenarios { t.Run(scenario.name, func(t *testing.T) { - eventRecorder := events.NewInMemoryRecorder("") + eventRecorder := events.NewInMemoryRecorder("", clocktesting.NewFakePassiveClock(time.Now())) fakeKubeClient := fake.NewSimpleClientset() target := &OAuthAPIServerWorkload{ diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go index 392d128c11..0daa62d309 100644 --- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go +++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go @@ -507,6 +507,20 @@ type AWSPlatformStatus struct { // +listType=atomic // +optional ResourceTags []AWSResourceTag `json:"resourceTags,omitempty"` + + // cloudLoadBalancerConfig holds configuration related to DNS and cloud + // load balancers. It allows configuration of in-cluster DNS as an alternative + // to the platform default DNS implementation. + // When using the ClusterHosted DNS type, Load Balancer IP addresses + // must be provided for the API and internal API load balancers as well as the + // ingress load balancer. + // + // +default={"dnsType": "PlatformDefault"} + // +kubebuilder:default={"dnsType": "PlatformDefault"} + // +openshift:enable:FeatureGate=AWSClusterHostedDNS + // +optional + // +nullable + CloudLoadBalancerConfig *CloudLoadBalancerConfig `json:"cloudLoadBalancerConfig,omitempty"` } // AWSResourceTag is a tag to apply to AWS resources created for the cluster. @@ -647,12 +661,12 @@ type GCPPlatformStatus struct { // Tombstone the field as a reminder. // ClusterHostedDNS ClusterHostedDNS `json:"clusterHostedDNS,omitempty"` - // cloudLoadBalancerConfig is a union that contains the IP addresses of API, - // API-Int and Ingress Load Balancers created on the cloud platform. These - // values would not be populated on on-prem platforms. These Load Balancer - // IPs are used to configure the in-cluster DNS instances for API, API-Int - // and Ingress services. `dnsType` is expected to be set to `ClusterHosted` - // when these Load Balancer IP addresses are populated and used. + // cloudLoadBalancerConfig holds configuration related to DNS and cloud + // load balancers. It allows configuration of in-cluster DNS as an alternative + // to the platform default DNS implementation. + // When using the ClusterHosted DNS type, Load Balancer IP addresses + // must be provided for the API and internal API load balancers as well as the + // ingress load balancer. // // +default={"dnsType": "PlatformDefault"} // +kubebuilder:default={"dnsType": "PlatformDefault"} diff --git a/vendor/github.com/openshift/api/config/v1/types_node.go b/vendor/github.com/openshift/api/config/v1/types_node.go index b3b1b62c4d..a50328c91f 100644 --- a/vendor/github.com/openshift/api/config/v1/types_node.go +++ b/vendor/github.com/openshift/api/config/v1/types_node.go @@ -46,6 +46,25 @@ type NodeSpec struct { // the status and corresponding reaction of the cluster // +optional WorkerLatencyProfile WorkerLatencyProfileType `json:"workerLatencyProfile,omitempty"` + + // minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + // Specifically, the apiserver will deny most authorization requests of kubelets that are older + // than the specified version, only allowing the kubelet to get and update its node object, and perform + // subjectaccessreviews. + // This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + // and will eventually be marked as not ready. + // Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + // Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + // the underlying kubernetes version this version of Openshift is based off of. + // In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + // they should set the minimumKubeletVersion to 1.30.0. + // When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + // Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + // +kubebuilder:validation:XValidation:rule="self == \"\" || self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="minmumKubeletVersion must be in a semver compatible format of x.y.z, or empty" + // +kubebuilder:validation:MaxLength:=8 + // +openshift:enable:FeatureGate=MinimumKubeletVersion + // +optional + MinimumKubeletVersion string `json:"minimumKubeletVersion"` } type NodeStatus struct { diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go index 0693469984..1b7fa44aad 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go @@ -245,6 +245,11 @@ func (in *AWSPlatformStatus) DeepCopyInto(out *AWSPlatformStatus) { *out = make([]AWSResourceTag, len(*in)) copy(*out, *in) } + if in.CloudLoadBalancerConfig != nil { + in, out := &in.CloudLoadBalancerConfig, &out.CloudLoadBalancerConfig + *out = new(CloudLoadBalancerConfig) + (*in).DeepCopyInto(*out) + } return } diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml index fa5dd4e31d..abfea5eaf0 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml @@ -310,6 +310,7 @@ infrastructures.config.openshift.io: Capability: "" Category: "" FeatureGates: + - AWSClusterHostedDNS - BareMetalLoadBalancer - GCPClusterHostedDNS - GCPLabelsTags @@ -382,7 +383,8 @@ nodes.config.openshift.io: CRDName: nodes.config.openshift.io Capability: "" Category: "" - FeatureGates: [] + FeatureGates: + - MinimumKubeletVersion FilenameOperatorName: config-operator FilenameOperatorOrdering: "01" FilenameRunLevel: "0000_10" diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index c580bd8342..145a7e4c04 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -1184,10 +1184,11 @@ func (AWSPlatformSpec) SwaggerDoc() map[string]string { } var map_AWSPlatformStatus = map[string]string{ - "": "AWSPlatformStatus holds the current status of the Amazon Web Services infrastructure provider.", - "region": "region holds the default AWS region for new AWS resources created by the cluster.", - "serviceEndpoints": "ServiceEndpoints list contains custom endpoints which will override default service endpoint of AWS Services. There must be only one ServiceEndpoint for a service.", - "resourceTags": "resourceTags is a list of additional tags to apply to AWS resources created for the cluster. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user.", + "": "AWSPlatformStatus holds the current status of the Amazon Web Services infrastructure provider.", + "region": "region holds the default AWS region for new AWS resources created by the cluster.", + "serviceEndpoints": "ServiceEndpoints list contains custom endpoints which will override default service endpoint of AWS Services. There must be only one ServiceEndpoint for a service.", + "resourceTags": "resourceTags is a list of additional tags to apply to AWS resources created for the cluster. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user.", + "cloudLoadBalancerConfig": "cloudLoadBalancerConfig holds configuration related to DNS and cloud load balancers. It allows configuration of in-cluster DNS as an alternative to the platform default DNS implementation. When using the ClusterHosted DNS type, Load Balancer IP addresses must be provided for the API and internal API load balancers as well as the ingress load balancer.", } func (AWSPlatformStatus) SwaggerDoc() map[string]string { @@ -1389,7 +1390,7 @@ var map_GCPPlatformStatus = map[string]string{ "region": "region holds the region for new GCP resources created for the cluster.", "resourceLabels": "resourceLabels is a list of additional labels to apply to GCP resources created for the cluster. See https://cloud.google.com/compute/docs/labeling-resources for information on labeling GCP resources. GCP supports a maximum of 64 labels per resource. OpenShift reserves 32 labels for internal use, allowing 32 labels for user configuration.", "resourceTags": "resourceTags is a list of additional tags to apply to GCP resources created for the cluster. See https://cloud.google.com/resource-manager/docs/tags/tags-overview for information on tagging GCP resources. GCP supports a maximum of 50 tags per resource.", - "cloudLoadBalancerConfig": "cloudLoadBalancerConfig is a union that contains the IP addresses of API, API-Int and Ingress Load Balancers created on the cloud platform. These values would not be populated on on-prem platforms. These Load Balancer IPs are used to configure the in-cluster DNS instances for API, API-Int and Ingress services. `dnsType` is expected to be set to `ClusterHosted` when these Load Balancer IP addresses are populated and used.", + "cloudLoadBalancerConfig": "cloudLoadBalancerConfig holds configuration related to DNS and cloud load balancers. It allows configuration of in-cluster DNS as an alternative to the platform default DNS implementation. When using the ClusterHosted DNS type, Load Balancer IP addresses must be provided for the API and internal API load balancers as well as the ingress load balancer.", } func (GCPPlatformStatus) SwaggerDoc() map[string]string { @@ -2087,8 +2088,9 @@ func (NodeList) SwaggerDoc() map[string]string { } var map_NodeSpec = map[string]string{ - "cgroupMode": "CgroupMode determines the cgroups version on the node", - "workerLatencyProfile": "WorkerLatencyProfile determins the how fast the kubelet is updating the status and corresponding reaction of the cluster", + "cgroupMode": "CgroupMode determines the cgroups version on the node", + "workerLatencyProfile": "WorkerLatencyProfile determins the how fast the kubelet is updating the status and corresponding reaction of the cluster", + "minimumKubeletVersion": "minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. Specifically, the apiserver will deny most authorization requests of kubelets that are older than the specified version, only allowing the kubelet to get and update its node object, and perform subjectaccessreviews. This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, and will eventually be marked as not ready. Its max length is 8, so maximum version allowed is either \"9.999.99\" or \"99.99.99\". Since the kubelet reports the version of the kubernetes release, not Openshift, this field references the underlying kubernetes version this version of Openshift is based off of. In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then they should set the minimumKubeletVersion to 1.30.0. When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. Thus, a kubelet with version \"1.0.0-ec.0\" will be compatible with minimumKubeletVersion \"1.0.0\" or earlier.", } func (NodeSpec) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_image_policy.go b/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_image_policy.go index e3670f03e8..14650fd48f 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_image_policy.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_image_policy.go @@ -41,6 +41,7 @@ type ClusterImagePolicySpec struct { // If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. // In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories // quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. + // If a scope is configured in both the ClusterImagePolicy and the ImagePolicy, or if the scope in ImagePolicy is nested under one of the scopes from the ClusterImagePolicy, only the policy from the ClusterImagePolicy will be applied. // For additional details about the format, please refer to the document explaining the docker transport field, // which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker // +kubebuilder:validation:Required diff --git a/vendor/github.com/openshift/api/config/v1alpha1/types_image_policy.go b/vendor/github.com/openshift/api/config/v1alpha1/types_image_policy.go index 7031110ff1..a177ddb0d6 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/types_image_policy.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/types_image_policy.go @@ -40,6 +40,7 @@ type ImagePolicySpec struct { // If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. // In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories // quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. + // If a scope is configured in both the ClusterImagePolicy and the ImagePolicy, or if the scope in ImagePolicy is nested under one of the scopes from the ClusterImagePolicy, only the policy from the ClusterImagePolicy will be applied. // For additional details about the format, please refer to the document explaining the docker transport field, // which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker // +kubebuilder:validation:Required diff --git a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go index 9da086efc5..55468f38da 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go @@ -102,7 +102,7 @@ func (ClusterImagePolicyList) SwaggerDoc() map[string]string { var map_ClusterImagePolicySpec = map[string]string{ "": "CLusterImagePolicySpec is the specification of the ClusterImagePolicy custom resource.", - "scopes": "scopes defines the list of image identities assigned to a policy. Each item refers to a scope in a registry implementing the \"Docker Registry HTTP API V2\". Scopes matching individual images are named Docker references in the fully expanded form, either using a tag or digest. For example, docker.io/library/busybox:latest (not busybox:latest). More general scopes are prefixes of individual-image scopes, and specify a repository (by omitting the tag or digest), a repository namespace, or a registry host (by only specifying the host name and possibly a port number) or a wildcard expression starting with `*.`, for matching all subdomains (not including a port number). Wildcards are only supported for subdomain matching, and may not be used in the middle of the host, i.e. *.example.com is a valid case, but example*.*.com is not. If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. For additional details about the format, please refer to the document explaining the docker transport field, which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker", + "scopes": "scopes defines the list of image identities assigned to a policy. Each item refers to a scope in a registry implementing the \"Docker Registry HTTP API V2\". Scopes matching individual images are named Docker references in the fully expanded form, either using a tag or digest. For example, docker.io/library/busybox:latest (not busybox:latest). More general scopes are prefixes of individual-image scopes, and specify a repository (by omitting the tag or digest), a repository namespace, or a registry host (by only specifying the host name and possibly a port number) or a wildcard expression starting with `*.`, for matching all subdomains (not including a port number). Wildcards are only supported for subdomain matching, and may not be used in the middle of the host, i.e. *.example.com is a valid case, but example*.*.com is not. If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. If a scope is configured in both the ClusterImagePolicy and the ImagePolicy, or if the scope in ImagePolicy is nested under one of the scopes from the ClusterImagePolicy, only the policy from the ClusterImagePolicy will be applied. For additional details about the format, please refer to the document explaining the docker transport field, which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker", "policy": "policy contains configuration to allow scopes to be verified, and defines how images not matching the verification policy will be treated.", } @@ -151,7 +151,7 @@ func (ImagePolicyList) SwaggerDoc() map[string]string { var map_ImagePolicySpec = map[string]string{ "": "ImagePolicySpec is the specification of the ImagePolicy CRD.", - "scopes": "scopes defines the list of image identities assigned to a policy. Each item refers to a scope in a registry implementing the \"Docker Registry HTTP API V2\". Scopes matching individual images are named Docker references in the fully expanded form, either using a tag or digest. For example, docker.io/library/busybox:latest (not busybox:latest). More general scopes are prefixes of individual-image scopes, and specify a repository (by omitting the tag or digest), a repository namespace, or a registry host (by only specifying the host name and possibly a port number) or a wildcard expression starting with `*.`, for matching all subdomains (not including a port number). Wildcards are only supported for subdomain matching, and may not be used in the middle of the host, i.e. *.example.com is a valid case, but example*.*.com is not. If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. For additional details about the format, please refer to the document explaining the docker transport field, which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker", + "scopes": "scopes defines the list of image identities assigned to a policy. Each item refers to a scope in a registry implementing the \"Docker Registry HTTP API V2\". Scopes matching individual images are named Docker references in the fully expanded form, either using a tag or digest. For example, docker.io/library/busybox:latest (not busybox:latest). More general scopes are prefixes of individual-image scopes, and specify a repository (by omitting the tag or digest), a repository namespace, or a registry host (by only specifying the host name and possibly a port number) or a wildcard expression starting with `*.`, for matching all subdomains (not including a port number). Wildcards are only supported for subdomain matching, and may not be used in the middle of the host, i.e. *.example.com is a valid case, but example*.*.com is not. If multiple scopes match a given image, only the policy requirements for the most specific scope apply. The policy requirements for more general scopes are ignored. In addition to setting a policy appropriate for your own deployed applications, make sure that a policy on the OpenShift image repositories quay.io/openshift-release-dev/ocp-release, quay.io/openshift-release-dev/ocp-v4.0-art-dev (or on a more general scope) allows deployment of the OpenShift images required for cluster operation. If a scope is configured in both the ClusterImagePolicy and the ImagePolicy, or if the scope in ImagePolicy is nested under one of the scopes from the ClusterImagePolicy, only the policy from the ClusterImagePolicy will be applied. For additional details about the format, please refer to the document explaining the docker transport field, which can be found at: https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md#docker", "policy": "policy contains configuration to allow scopes to be verified, and defines how images not matching the verification policy will be treated.", } diff --git a/vendor/github.com/openshift/api/envtest-releases.yaml b/vendor/github.com/openshift/api/envtest-releases.yaml index fa789b18ce..5651bbcc9d 100644 --- a/vendor/github.com/openshift/api/envtest-releases.yaml +++ b/vendor/github.com/openshift/api/envtest-releases.yaml @@ -12,3 +12,16 @@ releases: envtest-v1.30.3-linux-arm64.tar.gz: hash: deb395d5e9578a58786c42b4e7d878b4aef984ac2dce510031fbecf12092162a4aee1cde774f1527cfae90f6885382dc7b3d79ec379b7f4160c3a35fad7cbc3b selfLink: https://storage.googleapis.com/openshift-kubebuilder-tools/envtest-v1.30.3-linux-arm64.tar.gz + v1.31.1: + envtest-v1.31.1-darwin-amd64.tar.gz: + hash: c884c6a9751f12f57ede0dc3d8dfffdb0f60f7111d6d01ca0693b66d663dfbd37c21ab6a9e571d1a6f649ed7db54b04b069ab0aff6366b2db2f5d3d8ba84a296 + selfLink: https://storage.googleapis.com/openshift-kubebuilder-tools/envtest-v1.31.1-darwin-amd64.tar.gz + envtest-v1.31.1-darwin-arm64.tar.gz: + hash: c760be21c579a516cad8fbafd0f202229f5e074da1869958b84ae8dca295ffb33eb6fd4fd0b66349c31c4adff1561e7dd188137885e3661e34c0a14e12ada20e + selfLink: https://storage.googleapis.com/openshift-kubebuilder-tools/envtest-v1.31.1-darwin-arm64.tar.gz + envtest-v1.31.1-linux-amd64.tar.gz: + hash: a683fad736249b681d50c40715068ecb64f3ef22a85f29387eb61435c36dfe0cebf0bc7e109e237071cd856bc0e37d79a732309fd8d0b16fba6e019cf5c6e8b6 + selfLink: https://storage.googleapis.com/openshift-kubebuilder-tools/envtest-v1.31.1-linux-amd64.tar.gz + envtest-v1.31.1-linux-arm64.tar.gz: + hash: 86fa42c6a3d92e438e35d6066587d0e4f36b910885e10520868959ece2fe740d99abc735f69d6ebe8920291f70d3819b169ad5ddd2db805f8f56a3b83eee3893 + selfLink: https://storage.googleapis.com/openshift-kubebuilder-tools/envtest-v1.31.1-linux-arm64.tar.gz diff --git a/vendor/github.com/openshift/api/features.md b/vendor/github.com/openshift/api/features.md index e668fc88b3..660d3bff14 100644 --- a/vendor/github.com/openshift/api/features.md +++ b/vendor/github.com/openshift/api/features.md @@ -7,6 +7,7 @@ | MachineAPIOperatorDisableMachineHealthCheckController| | | | | | | | MultiArchInstallAzure| | | | | | | | GatewayAPI| | | Enabled | Enabled | | | +| AWSClusterHostedDNS| | | Enabled | Enabled | Enabled | Enabled | | AdditionalRoutingCapabilities| | | Enabled | Enabled | Enabled | Enabled | | AutomatedEtcdBackup| | | Enabled | Enabled | Enabled | Enabled | | BootcNodeManagement| | | Enabled | Enabled | Enabled | Enabled | @@ -18,6 +19,7 @@ | Example| | | Enabled | Enabled | Enabled | Enabled | | GCPClusterHostedDNS| | | Enabled | Enabled | Enabled | Enabled | | ImageStreamImportMode| | | Enabled | Enabled | Enabled | Enabled | +| IngressControllerDynamicConfigurationManager| | | Enabled | Enabled | Enabled | Enabled | | InsightsConfig| | | Enabled | Enabled | Enabled | Enabled | | InsightsConfigAPI| | | Enabled | Enabled | Enabled | Enabled | | InsightsOnDemandDataGather| | | Enabled | Enabled | Enabled | Enabled | @@ -27,6 +29,7 @@ | ManagedBootImagesAWS| | | Enabled | Enabled | Enabled | Enabled | | MaxUnavailableStatefulSet| | | Enabled | Enabled | Enabled | Enabled | | MetricsCollectionProfiles| | | Enabled | Enabled | Enabled | Enabled | +| MinimumKubeletVersion| | | Enabled | Enabled | Enabled | Enabled | | MixedCPUsAllocation| | | Enabled | Enabled | Enabled | Enabled | | NetworkSegmentation| | | Enabled | Enabled | Enabled | Enabled | | NewOLM| | | Enabled | Enabled | Enabled | Enabled | @@ -48,6 +51,7 @@ | UserNamespacesSupport| | | Enabled | Enabled | Enabled | Enabled | | VSphereMultiNetworks| | | Enabled | Enabled | Enabled | Enabled | | VSphereMultiVCenters| | | Enabled | Enabled | Enabled | Enabled | +| VolumeAttributesClass| | | Enabled | Enabled | Enabled | Enabled | | VolumeGroupSnapshot| | | Enabled | Enabled | Enabled | Enabled | | ExternalOIDC| Enabled | | Enabled | Enabled | Enabled | Enabled | | AWSEFSDriverVolumeMetrics| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | @@ -64,7 +68,6 @@ | IngressControllerLBSubnetsAWS| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | KMSv1| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | ManagedBootImages| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | -| MetricsServer| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | MultiArchInstallAWS| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | MultiArchInstallGCP| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | NetworkDiagnosticsConfig| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | diff --git a/vendor/github.com/openshift/api/features/features.go b/vendor/github.com/openshift/api/features/features.go index 7f49623954..0d1f0788e1 100644 --- a/vendor/github.com/openshift/api/features/features.go +++ b/vendor/github.com/openshift/api/features/features.go @@ -40,6 +40,7 @@ var ( reportProblemsToJiraComponent("apiserver-auth"). contactPerson("stlaz"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/4193"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -47,6 +48,7 @@ var ( reportProblemsToJiraComponent("kube-apiserver"). contactPerson("benluddy"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/3488"). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -54,6 +56,7 @@ var ( reportProblemsToJiraComponent("Routing"). contactPerson("miciah"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade). mustRegister() @@ -61,6 +64,7 @@ var ( reportProblemsToJiraComponent("Networking / router"). contactPerson("miheer"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -68,6 +72,7 @@ var ( reportProblemsToJiraComponent("auth"). contactPerson("ibihim"). productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/899"). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -75,6 +80,7 @@ var ( reportProblemsToJiraComponent("builds"). contactPerson("adkaplan"). productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1056"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -82,6 +88,7 @@ var ( reportProblemsToJiraComponent("builds"). contactPerson("adkaplan"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -89,6 +96,7 @@ var ( reportProblemsToJiraComponent("node"). contactPerson("ehashman"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/2400"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -96,6 +104,7 @@ var ( reportProblemsToJiraComponent("openstack"). contactPerson("egarcia"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -103,6 +112,7 @@ var ( reportProblemsToJiraComponent("insights"). contactPerson("tremes"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -110,6 +120,7 @@ var ( reportProblemsToJiraComponent("insights"). contactPerson("jmesnil"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -117,6 +128,7 @@ var ( reportProblemsToJiraComponent("scheduling"). contactPerson("jchaloup"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/4381"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -124,6 +136,7 @@ var ( reportProblemsToJiraComponent("cloud-credential-operator"). contactPerson("abutcher"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -131,6 +144,7 @@ var ( reportProblemsToJiraComponent("apps"). contactPerson("atiratree"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/961"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -138,12 +152,14 @@ var ( reportProblemsToJiraComponent("node"). contactPerson("sairameshv"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/3386"). mustRegister() FeatureGatePrivateHostedZoneAWS = newFeatureGate("PrivateHostedZoneAWS"). reportProblemsToJiraComponent("Routing"). contactPerson("miciah"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -151,6 +167,7 @@ var ( reportProblemsToJiraComponent("node"). contactPerson("sgrunert"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -158,6 +175,7 @@ var ( reportProblemsToJiraComponent("Installer"). contactPerson("bhb"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -165,6 +183,7 @@ var ( reportProblemsToJiraComponent("cloud-provider"). contactPerson("jspeed"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -172,6 +191,7 @@ var ( reportProblemsToJiraComponent("machine-config-operator/platform-baremetal"). contactPerson("mkowalsk"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/3705"). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -179,6 +199,7 @@ var ( reportProblemsToJiraComponent("splat"). contactPerson("vr4manta"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -186,6 +207,7 @@ var ( reportProblemsToJiraComponent("splat"). contactPerson("rvanderp3"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -193,6 +215,7 @@ var ( reportProblemsToJiraComponent("router"). contactPerson("thejasn"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -200,6 +223,7 @@ var ( reportProblemsToJiraComponent("Networking/ovn-kubernetes"). contactPerson("tssurya"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -207,6 +231,7 @@ var ( reportProblemsToJiraComponent("Networking/ovn-kubernetes"). contactPerson("tssurya"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -214,6 +239,7 @@ var ( reportProblemsToJiraComponent("Networking/cluster-network-operator"). contactPerson("jcaamano"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -221,6 +247,7 @@ var ( reportProblemsToJiraComponent("Networking/ovn-kubernetes"). contactPerson("jcaamano"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -228,6 +255,7 @@ var ( reportProblemsToJiraComponent("Networking/ovn-kubernetes"). contactPerson("pliu"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -235,6 +263,7 @@ var ( reportProblemsToJiraComponent("Networking/cluster-network-operator"). contactPerson("kyrtapz"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -242,6 +271,7 @@ var ( reportProblemsToJiraComponent("Networking"). contactPerson("npinaeva"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -249,6 +279,7 @@ var ( reportProblemsToJiraComponent("etcd"). contactPerson("hasbro17"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -256,6 +287,7 @@ var ( reportProblemsToJiraComponent("etcd"). contactPerson("hasbro17"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -263,6 +295,7 @@ var ( reportProblemsToJiraComponent("etcd"). contactPerson("hasbro17"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -270,12 +303,14 @@ var ( reportProblemsToJiraComponent("ecoproject"). contactPerson("msluiter"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). mustRegister() FeatureGateDNSNameResolver = newFeatureGate("DNSNameResolver"). reportProblemsToJiraComponent("dns"). contactPerson("miciah"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -283,6 +318,7 @@ var ( reportProblemsToJiraComponent("splat"). contactPerson("rvanderp3"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -290,6 +326,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("cdoern"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -297,19 +334,22 @@ var ( reportProblemsToJiraComponent("Installer"). contactPerson("vincepri"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). mustRegister() - FeatureGateMetricsServer = newFeatureGate("MetricsServer"). - reportProblemsToJiraComponent("Monitoring"). - contactPerson("slashpai"). + FeatureGateGCPClusterHostedDNS = newFeatureGate("GCPClusterHostedDNS"). + reportProblemsToJiraComponent("Installer"). + contactPerson("barbacbd"). productScope(ocpSpecific). - enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + enhancementPR(legacyFeatureGateWithoutEnhancement). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() - FeatureGateGCPClusterHostedDNS = newFeatureGate("GCPClusterHostedDNS"). + FeatureGateAWSClusterHostedDNS = newFeatureGate("AWSClusterHostedDNS"). reportProblemsToJiraComponent("Installer"). contactPerson("barbacbd"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -317,6 +357,7 @@ var ( reportProblemsToJiraComponent("NodeTuningOperator"). contactPerson("titzhak"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -324,6 +365,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("djoshy"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -331,6 +373,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("djoshy"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -338,6 +381,7 @@ var ( reportProblemsToJiraComponent("cloud-provider"). contactPerson("jspeed"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/2395"). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -345,6 +389,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("dkhater"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -352,6 +397,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("inesqyx"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -359,6 +405,7 @@ var ( reportProblemsToJiraComponent("Cluster Version Operator"). contactPerson("lmohanty"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -366,6 +413,7 @@ var ( reportProblemsToJiraComponent("kube-apiserver"). contactPerson("dgrisonnet"). productScope(kubernetes). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -373,6 +421,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("jhernand"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -380,6 +429,7 @@ var ( reportProblemsToJiraComponent("Cluster Version Operator"). contactPerson("pmuller"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -387,13 +437,23 @@ var ( reportProblemsToJiraComponent("kube-apiserver"). contactPerson("akashem"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/4006"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() + FeatureGateVolumeAttributesClass = newFeatureGate("VolumeAttributesClass"). + reportProblemsToJiraComponent("Storage / Kubernetes External Components"). + contactPerson("dfajmon"). + productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/3751"). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + mustRegister() + FeatureGateVolumeGroupSnapshot = newFeatureGate("VolumeGroupSnapshot"). reportProblemsToJiraComponent("Storage / Kubernetes External Components"). contactPerson("fbertina"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/3476"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -401,6 +461,7 @@ var ( reportProblemsToJiraComponent("authentication"). contactPerson("liouk"). productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1596"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). enableForClusterProfile(Hypershift, configv1.Default, configv1.TechPreviewNoUpgrade). mustRegister() @@ -409,6 +470,7 @@ var ( reportProblemsToJiraComponent("cluster-config"). contactPerson("deads"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -416,6 +478,7 @@ var ( reportProblemsToJiraComponent("olm"). contactPerson("joe"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -423,6 +486,7 @@ var ( reportProblemsToJiraComponent("olm"). contactPerson("joe"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -430,6 +494,7 @@ var ( reportProblemsToJiraComponent("insights"). contactPerson("tremes"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -437,6 +502,7 @@ var ( reportProblemsToJiraComponent("metal"). contactPerson("EmilienM"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -444,6 +510,7 @@ var ( reportProblemsToJiraComponent("insights"). contactPerson("tremes"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -451,6 +518,7 @@ var ( reportProblemsToJiraComponent("MachineConfigOperator"). contactPerson("jerzhang"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -458,6 +526,7 @@ var ( reportProblemsToJiraComponent("Monitoring"). contactPerson("rexagod"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -465,6 +534,7 @@ var ( reportProblemsToJiraComponent("Storage / Kubernetes External Components"). contactPerson("rbednar"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -472,12 +542,14 @@ var ( reportProblemsToJiraComponent("Installer"). contactPerson("cjschaef"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). mustRegister() FeatureGateChunkSizeMiB = newFeatureGate("ChunkSizeMiB"). reportProblemsToJiraComponent("Image Registry"). contactPerson("flavianmissi"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -485,12 +557,14 @@ var ( reportProblemsToJiraComponent("OCPCLOUD"). contactPerson("jspeed"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). mustRegister() FeatureGatePersistentIPsForVirtualization = newFeatureGate("PersistentIPsForVirtualization"). reportProblemsToJiraComponent("CNV Network"). contactPerson("mduarted"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -498,6 +572,7 @@ var ( reportProblemsToJiraComponent("Monitoring"). contactPerson("marioferh"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -505,6 +580,7 @@ var ( reportProblemsToJiraComponent("Installer"). contactPerson("r4f4"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -512,12 +588,14 @@ var ( reportProblemsToJiraComponent("Installer"). contactPerson("r4f4"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). mustRegister() FeatureGateMultiArchInstallGCP = newFeatureGate("MultiArchInstallGCP"). reportProblemsToJiraComponent("Installer"). contactPerson("r4f4"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -525,6 +603,7 @@ var ( reportProblemsToJiraComponent("Routing"). contactPerson("miciah"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -532,6 +611,7 @@ var ( reportProblemsToJiraComponent("Storage / Kubernetes External Components"). contactPerson("fbertina"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -539,6 +619,7 @@ var ( reportProblemsToJiraComponent("Multi-Arch"). contactPerson("psundara"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -546,6 +627,7 @@ var ( reportProblemsToJiraComponent("Node"). contactPerson("haircommander"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/127"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -553,6 +635,7 @@ var ( reportProblemsToJiraComponent("Node"). contactPerson("haircommander"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/127"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -560,6 +643,7 @@ var ( reportProblemsToJiraComponent("Node"). contactPerson("haircommander"). productScope(kubernetes). + enhancementPR("https://github.com/kubernetes/enhancements/issues/4265"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() @@ -567,6 +651,23 @@ var ( reportProblemsToJiraComponent("SPLAT"). contactPerson("rvanderp"). productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() + + FeatureGateIngressControllerDynamicConfigurationManager = newFeatureGate("IngressControllerDynamicConfigurationManager"). + reportProblemsToJiraComponent("Networking/router"). + contactPerson("miciah"). + productScope(ocpSpecific). + enhancementPR(legacyFeatureGateWithoutEnhancement). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + mustRegister() + + FeatureGateMinimumKubeletVersion = newFeatureGate("MinimumKubeletVersion"). + reportProblemsToJiraComponent("Node"). + contactPerson("haircommander"). + productScope(ocpSpecific). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + enhancementPR("https://github.com/openshift/enhancements/pull/1697"). + mustRegister() ) diff --git a/vendor/github.com/openshift/api/features/util.go b/vendor/github.com/openshift/api/features/util.go index d8d8e94a0e..3fd55bcdfe 100644 --- a/vendor/github.com/openshift/api/features/util.go +++ b/vendor/github.com/openshift/api/features/util.go @@ -3,6 +3,8 @@ package features import ( "fmt" configv1 "github.com/openshift/api/config/v1" + "net/url" + "strings" ) // FeatureGateDescription is a golang-only interface used to contains details for a feature gate. @@ -18,6 +20,8 @@ type FeatureGateDescription struct { ResponsiblePerson string // OwningProduct is the product that owns the lifecycle of the gate. OwningProduct OwningProduct + // EnhancementPR is the PR for the enhancement. + EnhancementPR string } type FeatureGateEnabledDisabled struct { @@ -45,10 +49,15 @@ type featureGateBuilder struct { owningJiraComponent string responsiblePerson string owningProduct OwningProduct + enhancementPRURL string statusByClusterProfileByFeatureSet map[ClusterProfileName]map[configv1.FeatureSet]bool } +const ( + legacyFeatureGateWithoutEnhancement = "FeatureGate predates 4.18" +) + // newFeatureGate featuregate are disabled in every FeatureSet and selectively enabled func newFeatureGate(name string) *featureGateBuilder { b := &featureGateBuilder{ @@ -80,6 +89,11 @@ func (b *featureGateBuilder) productScope(owningProduct OwningProduct) *featureG return b } +func (b *featureGateBuilder) enhancementPR(url string) *featureGateBuilder { + b.enhancementPRURL = url + return b +} + func (b *featureGateBuilder) enableIn(featureSets ...configv1.FeatureSet) *featureGateBuilder { for clusterProfile := range b.statusByClusterProfileByFeatureSet { for _, featureSet := range featureSets { @@ -109,6 +123,19 @@ func (b *featureGateBuilder) register() (configv1.FeatureGateName, error) { if len(b.owningProduct) == 0 { return "", fmt.Errorf("missing owningProduct") } + _, enhancementPRErr := url.Parse(b.enhancementPRURL) + switch { + case b.enhancementPRURL == legacyFeatureGateWithoutEnhancement: + + case len(b.enhancementPRURL) == 0: + return "", fmt.Errorf("FeatureGate/%s is missing an enhancementPR with GA Graduation Criteria like https://github.com/openshift/enhancements/pull/#### or https://github.com/kubernetes/enhancements/issues/####", b.name) + + case !strings.HasPrefix(b.enhancementPRURL, "https://github.com/openshift/enhancements/pull/") && !strings.HasPrefix(b.enhancementPRURL, "https://github.com/kubernetes/enhancements/issues/"): + return "", fmt.Errorf("FeatureGate/%s enhancementPR format is incorrect; must be like https://github.com/openshift/enhancements/pull/#### or https://github.com/kubernetes/enhancements/issues/####", b.name) + + case enhancementPRErr != nil: + return "", fmt.Errorf("FeatureGate/%s is enhancementPR is invalid: %w", b.name, enhancementPRErr) + } featureGateName := configv1.FeatureGateName(b.name) description := FeatureGateDescription{ @@ -118,6 +145,7 @@ func (b *featureGateBuilder) register() (configv1.FeatureGateName, error) { OwningJiraComponent: b.owningJiraComponent, ResponsiblePerson: b.responsiblePerson, OwningProduct: b.owningProduct, + EnhancementPR: b.enhancementPRURL, } // statusByClusterProfileByFeatureSet is initialized by constructor to be false for every combination diff --git a/vendor/github.com/openshift/api/kubecontrolplane/v1/types.go b/vendor/github.com/openshift/api/kubecontrolplane/v1/types.go index b9cdcc213b..6d29f42e3f 100644 --- a/vendor/github.com/openshift/api/kubecontrolplane/v1/types.go +++ b/vendor/github.com/openshift/api/kubecontrolplane/v1/types.go @@ -62,6 +62,25 @@ type KubeAPIServerConfig struct { // TODO this needs to be removed. APIServerArguments map[string]Arguments `json:"apiServerArguments"` + + // minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + // Specifically, the apiserver will deny most authorization requests of kubelets that are older + // than the specified version, only allowing the kubelet to get and update its node object, and perform + // subjectaccessreviews. + // This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + // and will eventually be marked as not ready. + // Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + // Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + // the underlying kubernetes version this version of Openshift is based off of. + // In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + // they should set the minimumKubeletVersion to 1.30.0. + // When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + // Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + // +kubebuilder:validation:XValidation:rule="self == \"\" || self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="minmumKubeletVersion must be in a semver compatible format of x.y.z, or empty" + // +kubebuilder:validation:MaxLength:=8 + // +openshift:enable:FeatureGate=MinimumKubeletVersion + // +optional + MinimumKubeletVersion string `json:"minimumKubeletVersion"` } // Arguments masks the value so protobuf can generate diff --git a/vendor/github.com/openshift/api/kubecontrolplane/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/kubecontrolplane/v1/zz_generated.swagger_doc_generated.go index 906bb271b0..5ecdd05839 100644 --- a/vendor/github.com/openshift/api/kubecontrolplane/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/kubecontrolplane/v1/zz_generated.swagger_doc_generated.go @@ -33,6 +33,7 @@ var map_KubeAPIServerConfig = map[string]string{ "projectConfig": "projectConfig feeds an admission plugin", "serviceAccountPublicKeyFiles": "serviceAccountPublicKeyFiles is a list of files, each containing a PEM-encoded public RSA key. (If any file contains a private key, the public portion of the key is used) The list of public keys is used to verify presented service account tokens. Each key is tried in order until the list is exhausted or verification succeeds. If no keys are specified, no service account authentication will be available.", "oauthConfig": "oauthConfig, if present start the /oauth endpoint in this process", + "minimumKubeletVersion": "minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. Specifically, the apiserver will deny most authorization requests of kubelets that are older than the specified version, only allowing the kubelet to get and update its node object, and perform subjectaccessreviews. This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, and will eventually be marked as not ready. Its max length is 8, so maximum version allowed is either \"9.999.99\" or \"99.99.99\". Since the kubelet reports the version of the kubernetes release, not Openshift, this field references the underlying kubernetes version this version of Openshift is based off of. In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then they should set the minimumKubeletVersion to 1.30.0. When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. Thus, a kubelet with version \"1.0.0-ec.0\" will be compatible with minimumKubeletVersion \"1.0.0\" or earlier.", } func (KubeAPIServerConfig) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/operator/v1/types.go b/vendor/github.com/openshift/api/operator/v1/types.go index eeb8afdc6d..f04b6846ae 100644 --- a/vendor/github.com/openshift/api/operator/v1/types.go +++ b/vendor/github.com/openshift/api/operator/v1/types.go @@ -147,17 +147,27 @@ type GenerationStatus struct { // group is the group of the thing you're tracking // +kubebuilder:validation:Required Group string `json:"group"` + // resource is the resource type of the thing you're tracking // +kubebuilder:validation:Required Resource string `json:"resource"` + // namespace is where the thing you're tracking is // +kubebuilder:validation:Required Namespace string `json:"namespace"` + // name is the name of the thing you're tracking // +kubebuilder:validation:Required Name string `json:"name"` + + // TODO: Add validation for lastGeneration. The value for this field should generally increase, except when the associated + // resource has been deleted and re-created. To accurately validate this field, we should introduce a new UID field and only + // enforce an increasing value in lastGeneration when the UID remains unchanged. A change in the UID indicates that the resource + // was re-created, allowing the lastGeneration value to reset or decrease. + // lastGeneration is the last generation of the workload controller involved LastGeneration int64 `json:"lastGeneration"` + // hash is an optional field set for resources without generation that are content sensitive like secrets and configmaps Hash string `json:"hash"` } @@ -178,12 +188,34 @@ var ( // OperatorCondition is just the standard condition fields. type OperatorCondition struct { + // type of condition in CamelCase or in foo.example.com/CamelCase. + // --- + // Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + // useful (see .node.status.conditions), the ability to deconflict is important. + // The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + // +required // +kubebuilder:validation:Required - Type string `json:"type"` - Status ConditionStatus `json:"status"` - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` - Reason string `json:"reason,omitempty"` - Message string `json:"message,omitempty"` + // +kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$` + // +kubebuilder:validation:MaxLength=316 + Type string `json:"type" protobuf:"bytes,1,opt,name=type"` + + // status of the condition, one of True, False, Unknown. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum=True;False;Unknown + Status ConditionStatus `json:"status"` + + // lastTransitionTime is the last time the condition transitioned from one status to another. + // This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Format=date-time + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + + Reason string `json:"reason,omitempty"` + + Message string `json:"message,omitempty"` } type ConditionStatus string diff --git a/vendor/github.com/openshift/api/operator/v1/types_ingress.go b/vendor/github.com/openshift/api/operator/v1/types_ingress.go index 7ae22ee0a7..1f56643456 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_ingress.go +++ b/vendor/github.com/openshift/api/operator/v1/types_ingress.go @@ -392,6 +392,7 @@ type CIDR string // LoadBalancerStrategy holds parameters for a load balancer. // +openshift:validation:FeatureGateAwareXValidation:featureGate=SetEIPForNLBIngressController,rule="!has(self.scope) || self.scope != 'Internal' || !has(self.providerParameters) || !has(self.providerParameters.aws) || !has(self.providerParameters.aws.networkLoadBalancer) || !has(self.providerParameters.aws.networkLoadBalancer.eipAllocations)",message="eipAllocations are forbidden when the scope is Internal." +// +kubebuilder:validation:XValidation:rule=`!has(self.scope) || self.scope != 'Internal' || !has(self.providerParameters) || !has(self.providerParameters.openstack) || !has(self.providerParameters.openstack.floatingIP) || self.providerParameters.openstack.floatingIP == ""`,message="cannot specify a floating ip when scope is internal" type LoadBalancerStrategy struct { // scope indicates the scope at which the load balancer is exposed. // Possible values are "External" and "Internal". @@ -678,19 +679,28 @@ type IBMLoadBalancerParameters struct { // OpenStackLoadBalancerParameters provides configuration settings that are // specific to OpenStack load balancers. type OpenStackLoadBalancerParameters struct { - // loadBalancerIP specifies the floating IP address that the load balancer will use. + // loadBalancerIP is tombstoned since the field was replaced by floatingIP. + // LoadBalancerIP string `json:"loadBalancerIP,omitempty"` + + // floatingIP specifies the IP address that the load balancer will use. // When not specified, an IP address will be assigned randomly by the OpenStack cloud provider. + // When specified, the floating IP has to be pre-created. If the + // specified value is not a floating IP or is already claimed, the + // OpenStack cloud provider won't be able to provision the load + // balancer. + // This field may only be used if the IngressController has External scope. // This value must be a valid IPv4 or IPv6 address. // + --- - // + Note: this field is meant to be set by the ingress controller to populate the - // + `Service.Spec.LoadBalancerIP` field which has been deprecated in Kubernetes: + // + Note: this field is meant to be set by the ingress controller + // + to populate the `Service.Spec.LoadBalancerIP` field which has been + // + deprecated in Kubernetes: // + https://github.com/kubernetes/kubernetes/pull/107235 // + However, the field is still used by cloud-provider-openstack to reconcile - // + the floating IP that we attach to the load balancer. + // + the floating IP that we attach to the external load balancer. // - // +kubebuilder:validation:XValidation:rule="isIP(self)",message="loadBalancerIP must be a valid IPv4 or IPv6 address" + // +kubebuilder:validation:XValidation:rule="isIP(self)",message="floatingIP must be a valid IPv4 or IPv6 address" // +optional - LoadBalancerIP string `json:"loadBalancerIP,omitempty"` + FloatingIP string `json:"floatingIP,omitempty"` } // AWSClassicLoadBalancerParameters holds configuration parameters for an diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_10_config-operator_01_configs.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_10_config-operator_01_configs.crd.yaml index c2d91226ab..323ba46879 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_10_config-operator_01_configs.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_10_config-operator_01_configs.crd.yaml @@ -110,6 +110,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -117,10 +120,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-CustomNoUpgrade.crd.yaml index afe82c37b3..b68cce4db3 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-CustomNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-CustomNoUpgrade.crd.yaml @@ -151,6 +151,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -158,10 +161,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-Default.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-Default.crd.yaml index f5df3557f8..ebe2486ef5 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-Default.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-Default.crd.yaml @@ -138,6 +138,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -145,10 +148,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-DevPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-DevPreviewNoUpgrade.crd.yaml index 3c01a3ce66..bc49df765d 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-DevPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-DevPreviewNoUpgrade.crd.yaml @@ -151,6 +151,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -158,10 +161,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-TechPreviewNoUpgrade.crd.yaml index cfaa4c7cea..8449c20a6c 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-TechPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_12_etcd_01_etcds-TechPreviewNoUpgrade.crd.yaml @@ -151,6 +151,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -158,10 +161,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml index da4ae9be68..435a8a81ee 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml @@ -128,6 +128,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -135,10 +138,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-controller-manager_01_kubecontrollermanagers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-controller-manager_01_kubecontrollermanagers.crd.yaml index 4cbd378af6..7cd18e09b5 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-controller-manager_01_kubecontrollermanagers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-controller-manager_01_kubecontrollermanagers.crd.yaml @@ -137,6 +137,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -144,10 +147,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-scheduler_01_kubeschedulers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-scheduler_01_kubeschedulers.crd.yaml index 255eab4c1b..9654facc4d 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-scheduler_01_kubeschedulers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_25_kube-scheduler_01_kubeschedulers.crd.yaml @@ -128,6 +128,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -135,10 +138,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_30_openshift-apiserver_01_openshiftapiservers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_30_openshift-apiserver_01_openshiftapiservers.crd.yaml index d2ae6f79a6..bb9b904fc5 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_30_openshift-apiserver_01_openshiftapiservers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_30_openshift-apiserver_01_openshiftapiservers.crd.yaml @@ -109,6 +109,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -116,10 +119,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_cloud-credential_00_cloudcredentials.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_cloud-credential_00_cloudcredentials.crd.yaml index 197b3f4e79..bf6c616afc 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_cloud-credential_00_cloudcredentials.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_cloud-credential_00_cloudcredentials.crd.yaml @@ -126,6 +126,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -133,10 +136,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_kube-storage-version-migrator_00_kubestorageversionmigrators.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_kube-storage-version-migrator_00_kubestorageversionmigrators.crd.yaml index 930f5506ad..30d1f90558 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_kube-storage-version-migrator_00_kubestorageversionmigrators.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_40_kube-storage-version-migrator_00_kubestorageversionmigrators.crd.yaml @@ -104,6 +104,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -111,10 +114,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_authentication_01_authentications.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_authentication_01_authentications.crd.yaml index 52fac7bef3..3fab2ff1f5 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_authentication_01_authentications.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_authentication_01_authentications.crd.yaml @@ -103,6 +103,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -110,10 +113,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_console_01_consoles.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_console_01_consoles.crd.yaml index 956c845472..505332e4b5 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_console_01_consoles.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_console_01_consoles.crd.yaml @@ -849,6 +849,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -856,10 +859,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml index 968febc36e..2524b5a84a 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml @@ -639,15 +639,20 @@ spec: If empty, defaults will be applied. See specific openstack fields for details about their defaults. properties: - loadBalancerIP: + floatingIP: description: |- - loadBalancerIP specifies the floating IP address that the load balancer will use. + floatingIP specifies the IP address that the load balancer will use. When not specified, an IP address will be assigned randomly by the OpenStack cloud provider. + When specified, the floating IP has to be pre-created. If the + specified value is not a floating IP or is already claimed, the + OpenStack cloud provider won't be able to provision the load + balancer. + This field may only be used if the IngressController has External scope. This value must be a valid IPv4 or IPv6 address. type: string x-kubernetes-validations: - - message: loadBalancerIP must be a valid IPv4 or - IPv6 address + - message: floatingIP must be a valid IPv4 or IPv6 + address rule: isIP(self) type: object type: @@ -689,6 +694,10 @@ spec: rule: '!has(self.scope) || self.scope != ''Internal'' || !has(self.providerParameters) || !has(self.providerParameters.aws) || !has(self.providerParameters.aws.networkLoadBalancer) || !has(self.providerParameters.aws.networkLoadBalancer.eipAllocations)' + - message: cannot specify a floating ip when scope is internal + rule: '!has(self.scope) || self.scope != ''Internal'' || !has(self.providerParameters) + || !has(self.providerParameters.openstack) || !has(self.providerParameters.openstack.floatingIP) + || self.providerParameters.openstack.floatingIP == ""' nodePort: description: |- nodePort holds parameters for the NodePortService endpoint publishing strategy. @@ -2336,6 +2345,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -2343,10 +2355,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array @@ -2815,15 +2837,20 @@ spec: If empty, defaults will be applied. See specific openstack fields for details about their defaults. properties: - loadBalancerIP: + floatingIP: description: |- - loadBalancerIP specifies the floating IP address that the load balancer will use. + floatingIP specifies the IP address that the load balancer will use. When not specified, an IP address will be assigned randomly by the OpenStack cloud provider. + When specified, the floating IP has to be pre-created. If the + specified value is not a floating IP or is already claimed, the + OpenStack cloud provider won't be able to provision the load + balancer. + This field may only be used if the IngressController has External scope. This value must be a valid IPv4 or IPv6 address. type: string x-kubernetes-validations: - - message: loadBalancerIP must be a valid IPv4 or - IPv6 address + - message: floatingIP must be a valid IPv4 or IPv6 + address rule: isIP(self) type: object type: @@ -2865,6 +2892,10 @@ spec: rule: '!has(self.scope) || self.scope != ''Internal'' || !has(self.providerParameters) || !has(self.providerParameters.aws) || !has(self.providerParameters.aws.networkLoadBalancer) || !has(self.providerParameters.aws.networkLoadBalancer.eipAllocations)' + - message: cannot specify a floating ip when scope is internal + rule: '!has(self.scope) || self.scope != ''Internal'' || !has(self.providerParameters) + || !has(self.providerParameters.openstack) || !has(self.providerParameters.openstack.floatingIP) + || self.providerParameters.openstack.floatingIP == ""' nodePort: description: |- nodePort holds parameters for the NodePortService endpoint publishing strategy. diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_insights_00_insightsoperators.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_insights_00_insightsoperators.crd.yaml index d1d2fa6b05..b7ce165e3f 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_insights_00_insightsoperators.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_insights_00_insightsoperators.crd.yaml @@ -108,6 +108,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -115,10 +118,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_openshift-controller-manager_02_openshiftcontrollermanagers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_openshift-controller-manager_02_openshiftcontrollermanagers.crd.yaml index 1abf8e03de..d6dabdda07 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_openshift-controller-manager_02_openshiftcontrollermanagers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_openshift-controller-manager_02_openshiftcontrollermanagers.crd.yaml @@ -106,6 +106,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -113,10 +116,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_service-ca_02_servicecas.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_service-ca_02_servicecas.crd.yaml index f31a18f210..16fba0d6d3 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_service-ca_02_servicecas.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_service-ca_02_servicecas.crd.yaml @@ -107,6 +107,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -114,10 +117,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_storage_01_storages.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_storage_01_storages.crd.yaml index b928c9137e..e0f8418814 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_storage_01_storages.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_storage_01_storages.crd.yaml @@ -123,6 +123,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -130,10 +133,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml index bdb32882b1..7d2acd004f 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml @@ -576,6 +576,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -583,10 +586,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml index c023c8c272..146c684056 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml @@ -923,6 +923,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -930,10 +933,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml index e1adf488a6..3f150defe7 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml @@ -867,6 +867,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -874,10 +877,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml index ce2db2e924..fd06797632 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml @@ -923,6 +923,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -930,10 +933,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml index 2704f6fbd0..e55b94afc3 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml @@ -923,6 +923,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -930,10 +933,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_80_csi-snapshot-controller_01_csisnapshotcontrollers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_80_csi-snapshot-controller_01_csisnapshotcontrollers.crd.yaml index 23197942ee..a166e4c3a7 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_80_csi-snapshot-controller_01_csisnapshotcontrollers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_80_csi-snapshot-controller_01_csisnapshotcontrollers.crd.yaml @@ -107,6 +107,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -114,10 +117,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_90_csi-driver_01_clustercsidrivers.crd.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_90_csi-driver_01_clustercsidrivers.crd.yaml index 1f0f61a943..9a65a695ac 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_90_csi-driver_01_clustercsidrivers.crd.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_90_csi-driver_01_clustercsidrivers.crd.yaml @@ -384,6 +384,9 @@ spec: description: OperatorCondition is just the standard condition fields. properties: lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: @@ -391,10 +394,20 @@ spec: reason: type: string status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - status - type type: object type: array diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go index a3a78a89b7..03d9e16edb 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go @@ -52,7 +52,10 @@ func (NodeStatus) SwaggerDoc() map[string]string { } var map_OperatorCondition = map[string]string{ - "": "OperatorCondition is just the standard condition fields.", + "": "OperatorCondition is just the standard condition fields.", + "type": "type of condition in CamelCase or in foo.example.com/CamelCase.", + "status": "status of the condition, one of True, False, Unknown.", + "lastTransitionTime": "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.", } func (OperatorCondition) SwaggerDoc() map[string]string { @@ -1122,8 +1125,8 @@ func (NodePortStrategy) SwaggerDoc() map[string]string { } var map_OpenStackLoadBalancerParameters = map[string]string{ - "": "OpenStackLoadBalancerParameters provides configuration settings that are specific to OpenStack load balancers.", - "loadBalancerIP": "loadBalancerIP specifies the floating IP address that the load balancer will use. When not specified, an IP address will be assigned randomly by the OpenStack cloud provider. This value must be a valid IPv4 or IPv6 address. ", + "": "OpenStackLoadBalancerParameters provides configuration settings that are specific to OpenStack load balancers.", + "floatingIP": "floatingIP specifies the IP address that the load balancer will use. When not specified, an IP address will be assigned randomly by the OpenStack cloud provider. When specified, the floating IP has to be pre-created. If the specified value is not a floating IP or is already claimed, the OpenStack cloud provider won't be able to provision the load balancer. This field may only be used if the IngressController has External scope. This value must be a valid IPv4 or IPv6 address. ", } func (OpenStackLoadBalancerParameters) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go index c0b4b77fe0..8390b7e784 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go @@ -3,6 +3,7 @@ package controllercmd import ( "context" "fmt" + "k8s.io/utils/clock" "os" "strings" "sync" @@ -40,6 +41,9 @@ type StartFunc func(context.Context, *ControllerContext) error type ControllerContext struct { ComponentConfig *unstructured.Unstructured + // Clock is a potentially fake clock that must be used to run controllers. + Clock clock.Clock + // KubeConfig provides the REST config with no content type (it will default to JSON). // Use this config for CR resources. KubeConfig *rest.Config @@ -71,6 +75,7 @@ type ControllerBuilder struct { fileObserverReactorFn func(file string, action fileobserver.ActionType) error eventRecorderOptions record.CorrelatorOptions componentOwnerReference *corev1.ObjectReference + clock clock.Clock startFunc StartFunc componentName string @@ -121,10 +126,11 @@ func (i infrastructureStatusTopologyDetector) DetectTopology(ctx context.Context var _ TopologyDetector = (*infrastructureStatusTopologyDetector)(nil) // NewController returns a builder struct for constructing the command you want to run -func NewController(componentName string, startFunc StartFunc) *ControllerBuilder { +func NewController(componentName string, startFunc StartFunc, clock clock.Clock) *ControllerBuilder { return &ControllerBuilder{ startFunc: startFunc, componentName: componentName, + clock: clock, observerInterval: defaultObserverInterval, nonZeroExitFn: func(args ...interface{}) { klog.Warning(args...) @@ -266,7 +272,7 @@ func (b *ControllerBuilder) Run(ctx context.Context, config *unstructured.Unstru klog.Warningf("unable to get owner reference (falling back to namespace): %v", err) } } - eventRecorder := events.NewKubeRecorderWithOptions(kubeClient.CoreV1().Events(namespace), b.eventRecorderOptions, b.componentName, controllerRef) + eventRecorder := events.NewKubeRecorderWithOptions(kubeClient.CoreV1().Events(namespace), b.eventRecorderOptions, b.componentName, controllerRef, b.clock) utilruntime.PanicHandlers = append(utilruntime.PanicHandlers, func(c context.Context, r interface{}) { eventRecorder.Warningf(fmt.Sprintf("%sPanic", strings.Title(b.componentName)), "Panic observed: %v", r) @@ -336,6 +342,7 @@ func (b *ControllerBuilder) Run(ctx context.Context, config *unstructured.Unstru controllerContext := &ControllerContext{ ComponentConfig: config, + Clock: b.clock, KubeConfig: clientConfig, ProtoKubeConfig: protoConfig, EventRecorder: eventRecorder, diff --git a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go index 8f3e4f5282..634053521c 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go @@ -3,6 +3,7 @@ package controllercmd import ( "context" "fmt" + "k8s.io/utils/clock" "math/rand" "os" "path/filepath" @@ -41,6 +42,7 @@ type ControllerCommandConfig struct { componentName string startFunc StartFunc version version.Info + clock clock.Clock basicFlags *ControllerFlags @@ -76,11 +78,12 @@ type ControllerCommandConfig struct { // NewControllerConfig returns a new ControllerCommandConfig which can be used to wire up all the boiler plate of a controller // TODO add more methods around wiring health checks and the like -func NewControllerCommandConfig(componentName string, version version.Info, startFunc StartFunc) *ControllerCommandConfig { +func NewControllerCommandConfig(componentName string, version version.Info, startFunc StartFunc, clock clock.Clock) *ControllerCommandConfig { return &ControllerCommandConfig{ startFunc: startFunc, componentName: componentName, version: version, + clock: clock, basicFlags: NewControllerFlags(), @@ -322,7 +325,7 @@ func (c *ControllerCommandConfig) StartController(ctx context.Context) error { config.LeaderElection.RenewDeadline = c.RenewDeadline config.LeaderElection.RetryPeriod = c.RetryPeriod - builder := NewController(c.componentName, c.startFunc). + builder := NewController(c.componentName, c.startFunc, c.clock). WithKubeConfigFile(c.basicFlags.KubeConfigFile, nil). WithComponentNamespace(c.basicFlags.Namespace). WithLeaderElection(config.LeaderElection, c.basicFlags.Namespace, c.componentName+"-lock"). diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/group_resource_discovery.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/group_resource_discovery.go index 6759302fa5..8d38883576 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/group_resource_discovery.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/group_resource_discovery.go @@ -4,32 +4,23 @@ import ( "errors" "fmt" "io/fs" - "k8s.io/apimachinery/pkg/util/json" "path/filepath" + + "k8s.io/apimachinery/pkg/util/json" "sigs.k8s.io/yaml" - "strings" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apirequest "k8s.io/apiserver/pkg/endpoints/request" ) func (mrt *manifestRoundTripper) getGroupResourceDiscovery(requestInfo *apirequest.RequestInfo) ([]byte, error) { switch { case requestInfo.Path == "/api": - ret, err := mrt.getAggregatedDiscoveryForURL("aggregated-discovery-api.yaml", requestInfo.Path) - if errors.Is(err, fs.ErrNotExist) { - return mrt.getLegacyGroupResourceDiscovery(requestInfo) - } - return ret, err + return mrt.getAggregatedDiscoveryForURL("aggregated-discovery-api.yaml", requestInfo.Path) case requestInfo.Path == "/apis": - ret, err := mrt.getAggregatedDiscoveryForURL("aggregated-discovery-apis.yaml", requestInfo.Path) - if errors.Is(err, fs.ErrNotExist) { - return mrt.getLegacyGroupResourceDiscovery(requestInfo) - } - return ret, err + return mrt.getAggregatedDiscoveryForURL("aggregated-discovery-apis.yaml", requestInfo.Path) default: // TODO can probably do better - return mrt.getLegacyGroupResourceDiscovery(requestInfo) + return nil, fmt.Errorf("unsupported discovery path: %q", requestInfo.Path) } } @@ -53,183 +44,3 @@ func (mrt *manifestRoundTripper) getAggregatedDiscoveryForURL(filename, url stri return apiJSON, err } - -func (mrt *manifestRoundTripper) getLegacyGroupResourceDiscovery(requestInfo *apirequest.RequestInfo) ([]byte, error) { - if len(requestInfo.Path) == 0 { - return nil, fmt.Errorf("path required for group resource discovery") - } - - apiResourceList := &metav1.APIResourceList{} - - group, version, err := splitGroupVersionFromRequestPath(requestInfo.Path) - if err != nil { - return nil, fmt.Errorf("unable to split group/version from path: %w", err) - } - - apiResourceList.GroupVersion = fmt.Sprintf("%s/%s", group, version) - if group == "core" { - apiResourceList.GroupVersion = version - } - - // Map of resource name to APIResource. - apiResources := map[string]metav1.APIResource{} - - clusterGroupPath := filepath.Join("cluster-scoped-resources", group) - clusterGroupDirEntries, err := fs.ReadDir(mrt.sourceFS, clusterGroupPath) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, fmt.Errorf("unable to read directory: %w", err) - } - - apiResourcesForClusterScope, err := getAPIResourcesFromNamespaceDirEntries(clusterGroupDirEntries, mrt.sourceFS, group, version, clusterGroupPath, false /* cluster-scoped */) - if err != nil { - return nil, fmt.Errorf("unable to get resources from cluster-scoped directory: %w", err) - } - for resourceName, apiResource := range apiResourcesForClusterScope { - apiResources[resourceName] = apiResource - } - - namespaceDirEntries, err := fs.ReadDir(mrt.sourceFS, "namespaces") - if err != nil { - return nil, fmt.Errorf("unable to read directory: %w", err) - } - for _, namespaceDirEntry := range namespaceDirEntries { - if !namespaceDirEntry.IsDir() { - continue - } - - namespaceGroupPath := filepath.Join("namespaces", namespaceDirEntry.Name(), group) - namespaceGroupDirEntries, err := fs.ReadDir(mrt.sourceFS, namespaceGroupPath) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, fmt.Errorf("unable to read directory: %w", err) - } else if errors.Is(err, fs.ErrNotExist) { - // No resources for this namespace. - continue - } - - apiResourcesForNamespace, err := getAPIResourcesFromNamespaceDirEntries(namespaceGroupDirEntries, mrt.sourceFS, group, version, namespaceGroupPath, true /* namespaced */) - if err != nil { - return nil, fmt.Errorf("unable to get resources from namespace directory: %w", err) - } - - for resourceName, apiResource := range apiResourcesForNamespace { - apiResources[resourceName] = apiResource - } - } - - for _, apiResource := range apiResources { - apiResourceList.APIResources = append(apiResourceList.APIResources, apiResource) - } - - ret, err := serializeAPIResourceListToJSON(apiResourceList) - if err != nil { - return nil, fmt.Errorf("failed to serialize group resource discovery: %v", err) - } - return []byte(ret), nil -} - -func splitGroupVersionFromRequestPath(path string) (string, string, error) { - if path == "/api/v1" { - return "core", "v1", nil - } - - parts := strings.Split(path, "/") - if len(parts) != 4 { - return "", "", fmt.Errorf("invalid path: %s", path) - } - - return parts[2], parts[3], nil -} - -func getResourceDirAPIServerListEntry(sourceFS fs.FS, groupPath, resourceName, group, version string, namespaced bool) (*metav1.APIResource, error) { - resourceDirEntries, err := fs.ReadDir(sourceFS, filepath.Join(groupPath, resourceName)) - if err != nil { - return nil, fmt.Errorf("unable to read directory: %w", err) - } - for _, fileEntry := range resourceDirEntries { - if !strings.HasSuffix(fileEntry.Name(), ".yaml") { - // There shouldn't be anything that hits this, but ignore it if there is. - continue - } - - individualObj, individualErr := readIndividualFile(sourceFS, filepath.Join(groupPath, resourceName, fileEntry.Name())) - if individualErr != nil { - return nil, fmt.Errorf("unable to read file: %w", individualErr) - } - - groupVersion := fmt.Sprintf("%s/%s", group, version) - if group == "core" { - group = "" - groupVersion = version - } - - if individualObj.GetAPIVersion() != groupVersion { - continue - } - - // No point checking further, all files should produce the same APIResource. - return &metav1.APIResource{ - Name: resourceName, - Kind: individualObj.GetKind(), - Group: group, - Version: version, - Namespaced: namespaced, - Verbs: []string{"get", "list", "watch"}, - }, nil - } - - return nil, nil -} - -func getAPIResourcesFromNamespaceDirEntries(dirEntries []fs.DirEntry, sourceFS fs.FS, group, version string, basePath string, namespaced bool) (map[string]metav1.APIResource, error) { - apiResources := map[string]metav1.APIResource{} - for _, dirEntry := range dirEntries { - // Directories are named after the resource and contain individual resources. - if dirEntry.IsDir() { - apiResource, err := getResourceDirAPIServerListEntry(sourceFS, basePath, dirEntry.Name(), group, version, namespaced) - if err != nil { - return nil, fmt.Errorf("unable to get resource from directory: %w", err) - } - if apiResource != nil { - apiResources[dirEntry.Name()] = *apiResource - } - } - - if !strings.HasSuffix(dirEntry.Name(), ".yaml") { - // There shouldn't be anything that hits this, but ignore it if there is. - continue - } - - resourceName := strings.TrimSuffix(dirEntry.Name(), ".yaml") - if _, ok := apiResources[resourceName]; ok { - // We already have this resource. - continue - } - - // Files are named after the resource and contain a list of resources. - listObj, err := readListFile(sourceFS, filepath.Join(basePath, dirEntry.Name())) - if err != nil { - return nil, fmt.Errorf("unable to read list file: %w", err) - } - - for _, obj := range listObj.Items { - if obj.GetAPIVersion() != fmt.Sprintf("%s/%s", group, version) { - continue - } - - apiResources[resourceName] = metav1.APIResource{ - Name: resourceName, - Kind: obj.GetKind(), - Group: group, - Version: version, - Namespaced: namespaced, - Verbs: []string{"get", "list", "watch"}, - } - - // Once we find a resource in the expected group/version, we can break. - // Anything else would produce the same APIResource. - break - } - } - - return apiResources, nil -} diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/list.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/list.go index f24890eb41..3a80bafaaa 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/list.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/list.go @@ -4,10 +4,11 @@ import ( "errors" "fmt" "io/fs" - "k8s.io/apimachinery/pkg/runtime/schema" "path/filepath" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" apirequest "k8s.io/apiserver/pkg/endpoints/request" ) @@ -74,6 +75,10 @@ func (mrt *manifestRoundTripper) listAll(requestInfo *apirequest.RequestInfo) ([ if retList.GroupVersionKind() != kind.listKind { return nil, fmt.Errorf("inconsistent list kind: got %v, expected %v", retList.GroupVersionKind(), kind.listKind) } + retList, err := filterByLabelSelector(retList, requestInfo.LabelSelector) + if err != nil { + return nil, fmt.Errorf("failed to filter by labelSelector %s: %w", requestInfo.LabelSelector, err) + } ret, err := serializeListObjToJSON(retList) if err != nil { return nil, fmt.Errorf("failed to serialize: %v", err) @@ -109,6 +114,10 @@ func (mrt *manifestRoundTripper) listAll(requestInfo *apirequest.RequestInfo) ([ if retList.Items[0].GroupVersionKind() != kind.kind { return nil, fmt.Errorf("inconsistent item kind: got %v, expected %v", retList.Items[0].GroupVersionKind(), kind.kind) } + retList, err := filterByLabelSelector(retList, requestInfo.LabelSelector) + if err != nil { + return nil, fmt.Errorf("failed to filter by labelSelector %s: %w", requestInfo.LabelSelector, err) + } ret, err := serializeListObjToJSON(retList) if err != nil { return nil, fmt.Errorf("failed to serialize: %v", err) @@ -231,7 +240,10 @@ func allPossibleListFileLocations(sourceFS fs.FS, requestInfo *apirequest.Reques allPossibleListFileLocations = append(allPossibleListFileLocations, filepath.Join(clusterParts...)) namespaces, err := allNamespacesWithData(sourceFS) - if err != nil { + switch { + case errors.Is(err, fs.ErrNotExist): + return allPossibleListFileLocations, nil + case err != nil: return nil, fmt.Errorf("unable to read namespaces: %w", err) } for _, ns := range namespaces { @@ -270,3 +282,26 @@ func allPossibleNamespaceFiles(sourceFS fs.FS) ([]string, error) { return allPossibleListFileLocations, nil } + +func filterByLabelSelector(list *unstructured.UnstructuredList, labelSelector string) (*unstructured.UnstructuredList, error) { + if labelSelector == "" { + return list, nil + } + + parsedSelector, err := labels.Parse(labelSelector) + if err != nil { + return nil, err + } + + var filteredItems []unstructured.Unstructured + for _, item := range list.Items { + if parsedSelector.Matches(labels.Set(item.GetLabels())) { + filteredItems = append(filteredItems, item) + } + } + + return &unstructured.UnstructuredList{ + Object: list.Object, + Items: filteredItems, + }, nil +} diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_reader.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_reader.go index 18990eca26..2f0a8c649a 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_reader.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_reader.go @@ -4,15 +4,15 @@ import ( "errors" "fmt" "io/fs" + "k8s.io/apimachinery/pkg/runtime/schema" "os" "path/filepath" "regexp" + "sigs.k8s.io/yaml" "strings" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" - "sigs.k8s.io/yaml" ) func ReadMutationDirectory(mutationDirectory string) (*AllActionsTracker[FileOriginatedSerializedRequest], error) { @@ -95,8 +95,8 @@ func readSerializedRequestsFromActionDirectory(action Action, actionFS fs.FS) ([ } var ( - bodyRegex = regexp.MustCompile(`(\d\d\d)-body-(.+).yaml`) - optionsRegex = regexp.MustCompile(`(\d\d\d)-options-(.+).yaml`) + bodyRegex = regexp.MustCompile(`.*-body-(.+).yaml`) + optionsRegex = regexp.MustCompile(`.*-options-(.+).yaml`) ) func serializedRequestFromFile(action Action, actionFS fs.FS, bodyFilename string) (*FileOriginatedSerializedRequest, error) { @@ -106,12 +106,23 @@ func serializedRequestFromFile(action Action, actionFS fs.FS, bodyFilename strin } optionsBaseName := strings.Replace(bodyBasename, "body", "options", 1) optionsFilename := filepath.Join(filepath.Dir(bodyFilename), optionsBaseName) + metadataBaseName := strings.Replace(bodyBasename, "body", "metadata", 1) + metadataFilename := filepath.Join(filepath.Dir(bodyFilename), metadataBaseName) bodyContent, err := fs.ReadFile(actionFS, bodyFilename) if err != nil { return nil, fmt.Errorf("failed to read %q: %w", bodyFilename, err) } + metadataContent, err := fs.ReadFile(actionFS, metadataFilename) + if err != nil { + return nil, fmt.Errorf("failed to read %q: %w", metadataFilename, err) + } + metadataFromFile := &ActionMetadata{} + if err := yaml.Unmarshal(metadataContent, metadataFromFile); err != nil { + return nil, fmt.Errorf("failed to parse %q: %w", metadataFilename, err) + } + optionsExist := false optionsContent, err := fs.ReadFile(actionFS, optionsFilename) switch { @@ -124,46 +135,30 @@ func serializedRequestFromFile(action Action, actionFS fs.FS, bodyFilename strin } // parse to discover bits of the serialized request - retObj, _, jsonErr := unstructured.UnstructuredJSONScheme.Decode(bodyContent, nil, &unstructured.Unstructured{}) - if jsonErr != nil { - // try to see if it's yaml - jsonString, err := yaml.YAMLToJSON(bodyContent) - if err != nil { - return nil, fmt.Errorf("unable to decode %q as json: %w", bodyFilename, jsonErr) - } - retObj, _, err = unstructured.UnstructuredJSONScheme.Decode(jsonString, nil, &unstructured.Unstructured{}) - if err != nil { - return nil, fmt.Errorf("unable to decode %q as yaml: %w", bodyFilename, err) + kindType := schema.GroupVersionKind{} + actionHasRuntimeObjectBody := action != ActionPatch && action != ActionPatchStatus + if actionHasRuntimeObjectBody { + retObj, _, jsonErr := unstructured.UnstructuredJSONScheme.Decode(bodyContent, nil, &unstructured.Unstructured{}) + if jsonErr != nil { + // try to see if it's yaml + jsonString, err := yaml.YAMLToJSON(bodyContent) + if err != nil { + return nil, fmt.Errorf("unable to decode %q as json: %w", bodyFilename, jsonErr) + } + retObj, _, err = unstructured.UnstructuredJSONScheme.Decode(jsonString, nil, &unstructured.Unstructured{}) + if err != nil { + return nil, fmt.Errorf("unable to decode %q as yaml: %w", bodyFilename, err) + } + kindType = retObj.(*unstructured.Unstructured).GroupVersionKind() } } - // stepping backwards in the filename we can determine resource and group since we're using individual files, not lists - resourceName := filepath.Base(filepath.Dir(bodyFilename)) - versionName := retObj.(*unstructured.Unstructured).GroupVersionKind().Version // not always correct, but nearly always correct. When/if we get to scale this will be interesting - groupName := filepath.Base(filepath.Dir(filepath.Dir(bodyFilename))) - if groupName == "core" { - groupName = "" - } - - metadataName := retObj.(*unstructured.Unstructured).GetName() - if action == ActionDelete { - metadataName = retObj.(*unstructured.Unstructured).GetAnnotations()[DeletionNameAnnotation] - } - ret := &FileOriginatedSerializedRequest{ BodyFilename: bodyFilename, SerializedRequest: SerializedRequest{ - Action: action, - ResourceType: schema.GroupVersionResource{ - Group: groupName, - Version: versionName, - Resource: resourceName, - }, - KindType: retObj.(*unstructured.Unstructured).GroupVersionKind(), - Namespace: retObj.(*unstructured.Unstructured).GetNamespace(), - Name: metadataName, - GenerateName: retObj.(*unstructured.Unstructured).GetGenerateName(), - Body: bodyContent, + ActionMetadata: *metadataFromFile, + KindType: kindType, + Body: bodyContent, }, } if optionsExist { diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_writer.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_writer.go index 39800058bb..cac4c3c722 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_writer.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_directory_writer.go @@ -5,20 +5,32 @@ import ( "fmt" "os" "path/filepath" + "sigs.k8s.io/yaml" ) func WriteMutationDirectory[T SerializedRequestish](mutationDirectory string, requests ...T) error { errs := []error{} for _, request := range requests { - bodyFilename, optionsFilename := request.SuggestedFilenames() + metadataFilename, bodyFilename, optionsFilename := request.SuggestedFilenames() bodyPath := filepath.Join(mutationDirectory, bodyFilename) + metadataPath := filepath.Join(mutationDirectory, metadataFilename) + + metadataBytes, err := yaml.Marshal(request.GetSerializedRequest().GetLookupMetadata()) + if err != nil { + errs = append(errs, fmt.Errorf("unable to serialize metadata %v: %w", request.GetSerializedRequest().ActionMetadata, err)) + continue + } parentDir := filepath.Dir(bodyPath) if err := os.MkdirAll(parentDir, 0755); err != nil { errs = append(errs, fmt.Errorf("unable to create parentDir %q: %w", parentDir, err)) continue } + + if err := os.WriteFile(metadataPath, metadataBytes, 0644); err != nil { + errs = append(errs, fmt.Errorf("unable to write body %v: %w", request, err)) + } if err := os.WriteFile(bodyPath, request.GetSerializedRequest().Body, 0644); err != nil { errs = append(errs, fmt.Errorf("unable to write body %v: %w", request, err)) } diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_tracker.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_tracker.go index b445d78eaf..753fb30f57 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_tracker.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/mutation_tracker.go @@ -12,6 +12,8 @@ type Action string const ( // this is really a subset of patch, but we treat it separately because it is useful to do so + ActionPatch Action = "Patch" + ActionPatchStatus Action = "PatchStatus" ActionApply Action = "Apply" ActionApplyStatus Action = "ApplyStatus" ActionUpdate Action = "Update" @@ -22,6 +24,8 @@ const ( var ( AllActions = sets.New[Action]( + ActionPatch, + ActionPatchStatus, ActionApply, ActionApplyStatus, ActionUpdate, @@ -36,11 +40,21 @@ type AllActionsTracker[T SerializedRequestish] struct { } type ActionMetadata struct { - Action Action - GVR schema.GroupVersionResource - Namespace string - Name string - GenerateName string + Action Action `json:"action"` + ResourceMetadata `json:",inline"` + + PatchType string `json:"patchType,omitempty"` + FieldManager string `json:"fieldManager,omitempty"` + ControllerInstanceName string `json:"controllerInstanceName"` +} + +// ResourceMetadata uniquely identifies an item in the API +// This is probably shareable across multiple packages. +type ResourceMetadata struct { + ResourceType schema.GroupVersionResource `json:"resourceType"` + Namespace string `json:"namespace,omitempty"` + Name string `json:"mame"` + GenerateName string `json:"generateName"` } type actionTracker[T SerializedRequestish] struct { diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/read_roundtripper.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/read_roundtripper.go index 77d5beb5e4..4f798e5c27 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/read_roundtripper.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/read_roundtripper.go @@ -6,21 +6,30 @@ import ( "fmt" "io" "io/fs" - apidiscoveryv2 "k8s.io/api/apidiscovery/v2" - "k8s.io/apimachinery/pkg/util/json" "net/http" "strconv" "strings" "sync" "time" + apidiscoveryv2 "k8s.io/api/apidiscovery/v2" + "k8s.io/apimachinery/pkg/util/json" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/server" + utilfeature "k8s.io/apiserver/pkg/util/feature" ) +func init() { + // This feature gate is needed to set requestInfo.LabelSelector + utilruntime.Must(utilfeature.DefaultMutableFeatureGate.Set(fmt.Sprintf("%s=true", features.AuthorizeWithSelectors))) +} + type manifestRoundTripper struct { sourceFS fs.FS @@ -58,7 +67,7 @@ func (mrt *manifestRoundTripper) RoundTrip(req *http.Request) (*http.Response, e isDiscovery := isServerGroupResourceDiscovery(requestInfo.Path) if !requestInfo.IsResourceRequest && !isDiscovery { - return nil, fmt.Errorf("non-resource requests are not supported by this implementation") + return nil, fmt.Errorf("non-resource requests are not supported by this implementation: %q", requestInfo.Path) } if len(requestInfo.Subresource) != 0 { return nil, fmt.Errorf("subresource %v is not supported by this implementation", requestInfo.Subresource) @@ -104,7 +113,9 @@ func (mrt *manifestRoundTripper) RoundTrip(req *http.Request) (*http.Response, e return nil, fmt.Errorf("verb %v is not supported by this implementation", requestInfo.Verb) } - resp := &http.Response{} + resp := &http.Response{ + Header: map[string][]string{}, + } switch { case apierrors.IsNotFound(returnErr): resp.StatusCode = http.StatusNotFound @@ -120,7 +131,11 @@ func (mrt *manifestRoundTripper) RoundTrip(req *http.Request) (*http.Response, e resp.Body = io.NopCloser(bytes.NewReader(returnBody)) // We always return application/json. Avoid clients expecting proto for built-ins. resp.Header = make(http.Header) - resp.Header.Set("Content-Type", "application/json") + if isDiscovery { + resp.Header.Set("Content-Type", "application/json;as=APIGroupDiscoveryList;v=v2;g=apidiscovery.k8s.io") + } else { + resp.Header.Set("Content-Type", "application/json") + } } return resp, nil @@ -143,6 +158,9 @@ func isServerGroupResourceDiscovery(path string) bool { if path == "/api" { return true } + if path == "/apis" { + return true + } parts := strings.Split(path, "/") if len(parts) != 4 { diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/serialized_request.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/serialized_request.go index 1420fd9ed0..7023ed3566 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/serialized_request.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/serialized_request.go @@ -2,6 +2,7 @@ package manifestclient import ( "bytes" + "crypto/sha256" "fmt" "path/filepath" "strings" @@ -11,13 +12,14 @@ import ( type SerializedRequestish interface { GetSerializedRequest() *SerializedRequest - SuggestedFilenames() (string, string) + SuggestedFilenames() (string, string, string) DeepCopy() SerializedRequestish } type FileOriginatedSerializedRequest struct { - BodyFilename string - OptionsFilename string + MetadataFilename string + BodyFilename string + OptionsFilename string SerializedRequest SerializedRequest } @@ -29,12 +31,8 @@ type TrackedSerializedRequest struct { } type SerializedRequest struct { - Action Action - ResourceType schema.GroupVersionResource - KindType schema.GroupVersionKind - Namespace string - Name string - GenerateName string + ActionMetadata + KindType schema.GroupVersionKind Options []byte Body []byte @@ -130,6 +128,9 @@ func CompareFileOriginatedSerializedRequest(lhs, rhs *FileOriginatedSerializedRe if cmp := CompareSerializedRequest(&lhs.SerializedRequest, &rhs.SerializedRequest); cmp != 0 { return cmp } + if cmp := strings.Compare(lhs.MetadataFilename, rhs.MetadataFilename); cmp != 0 { + return cmp + } if cmp := strings.Compare(lhs.BodyFilename, rhs.BodyFilename); cmp != 0 { return cmp } @@ -180,6 +181,15 @@ func CompareSerializedRequest(lhs, rhs *SerializedRequest) int { if cmp := strings.Compare(string(lhs.Action), string(rhs.Action)); cmp != 0 { return cmp } + if cmp := strings.Compare(lhs.PatchType, rhs.PatchType); cmp != 0 { + return cmp + } + if cmp := strings.Compare(lhs.FieldManager, rhs.FieldManager); cmp != 0 { + return cmp + } + if cmp := strings.Compare(lhs.ControllerInstanceName, rhs.ControllerInstanceName); cmp != 0 { + return cmp + } if cmp := strings.Compare(lhs.ResourceType.Group, rhs.ResourceType.Group); cmp != 0 { return cmp @@ -233,21 +243,21 @@ func (a SerializedRequest) GetSerializedRequest() *SerializedRequest { return &a } -func (a FileOriginatedSerializedRequest) SuggestedFilenames() (string, string) { - return a.BodyFilename, a.OptionsFilename +func (a FileOriginatedSerializedRequest) SuggestedFilenames() (string, string, string) { + return a.MetadataFilename, a.BodyFilename, a.OptionsFilename } -func (a TrackedSerializedRequest) SuggestedFilenames() (string, string) { - return suggestedFilenames(a.SerializedRequest, a.RequestNumber) +func (a TrackedSerializedRequest) SuggestedFilenames() (string, string, string) { + return suggestedFilenames(a.SerializedRequest) } -func (a SerializedRequest) SuggestedFilenames() (string, string) { - // this may very well conflict in some cases. Up to the caller to work out how to fix it. - uniqueNumber := 0 // chosen by fair dice roll. guaranteed to be random. :) - return suggestedFilenames(a, uniqueNumber) +func (a SerializedRequest) SuggestedFilenames() (string, string, string) { + return suggestedFilenames(a) } -func suggestedFilenames(a SerializedRequest, uniqueNumber int) (string, string) { +func suggestedFilenames(a SerializedRequest) (string, string, string) { + bodyHash := hashRequestToPrefix(a.Body, a.Options) + groupName := a.ResourceType.Group if len(groupName) == 0 { groupName = "core" @@ -260,13 +270,22 @@ func suggestedFilenames(a SerializedRequest, uniqueNumber int) (string, string) scopingString = filepath.Join("cluster-scoped-resources") } + metadataFilename := MakeFilenameGoModSafe( + filepath.Join( + string(a.Action), + scopingString, + groupName, + a.ResourceType.Resource, + fmt.Sprintf("%s-metadata-%s%s.yaml", bodyHash, a.Name, a.GenerateName), + ), + ) bodyFilename := MakeFilenameGoModSafe( filepath.Join( string(a.Action), scopingString, groupName, a.ResourceType.Resource, - fmt.Sprintf("%03d-body-%s%s.yaml", uniqueNumber, a.Name, a.GenerateName), + fmt.Sprintf("%s-body-%s%s.yaml", bodyHash, a.Name, a.GenerateName), ), ) optionsFilename := "" @@ -277,15 +296,39 @@ func suggestedFilenames(a SerializedRequest, uniqueNumber int) (string, string) scopingString, groupName, a.ResourceType.Resource, - fmt.Sprintf("%03d-options-%s%s.yaml", uniqueNumber, a.Name, a.GenerateName), + fmt.Sprintf("%s-options-%s%s.yaml", bodyHash, a.Name, a.GenerateName), ), ) } - return bodyFilename, optionsFilename + return metadataFilename, bodyFilename, optionsFilename +} + +func hashRequestToPrefix(data, options []byte) string { + switch { + case len(data) > 0: + return hashForFilenamePrefix(data) + case len(options) > 0: + return hashForFilenamePrefix(options) + default: + return "MISSING" + } +} + +func hashForFilenamePrefix(data []byte) string { + if len(data) == 0 { + return "MISSING" + } + hash := sha256.New() + hash.Write(data) + hashBytes := hash.Sum(nil) + + // we're looking to deconflict filenames, not protect the crown jewels + return fmt.Sprintf("%x", hashBytes[len(hashBytes)-2:]) } func (a FileOriginatedSerializedRequest) DeepCopy() SerializedRequestish { return FileOriginatedSerializedRequest{ + MetadataFilename: a.MetadataFilename, BodyFilename: a.BodyFilename, OptionsFilename: a.OptionsFilename, SerializedRequest: a.SerializedRequest.DeepCopy().(SerializedRequest), @@ -301,14 +344,21 @@ func (a TrackedSerializedRequest) DeepCopy() SerializedRequestish { func (a SerializedRequest) DeepCopy() SerializedRequestish { return SerializedRequest{ - Action: a.Action, - ResourceType: a.ResourceType, - KindType: a.KindType, - Namespace: a.Namespace, - Name: a.Name, - GenerateName: a.GenerateName, - Options: bytes.Clone(a.Options), - Body: bytes.Clone(a.Body), + ActionMetadata: ActionMetadata{ + Action: a.Action, + ResourceMetadata: ResourceMetadata{ + ResourceType: a.ResourceType, + Namespace: a.Namespace, + Name: a.Name, + GenerateName: a.GenerateName, + }, + PatchType: a.PatchType, + FieldManager: a.FieldManager, + ControllerInstanceName: a.ControllerInstanceName, + }, + KindType: a.KindType, + Options: bytes.Clone(a.Options), + Body: bytes.Clone(a.Body), } } @@ -317,11 +367,5 @@ func (a SerializedRequest) StringID() string { } func (a SerializedRequest) GetLookupMetadata() ActionMetadata { - return ActionMetadata{ - Action: a.Action, - GVR: a.ResourceType, - Namespace: a.Namespace, - Name: a.Name, - GenerateName: a.GenerateName, - } + return a.ActionMetadata } diff --git a/vendor/github.com/openshift/library-go/pkg/manifestclient/write_roundtripper.go b/vendor/github.com/openshift/library-go/pkg/manifestclient/write_roundtripper.go index 9b2e88b7fe..a75dd8a4ae 100644 --- a/vendor/github.com/openshift/library-go/pkg/manifestclient/write_roundtripper.go +++ b/vendor/github.com/openshift/library-go/pkg/manifestclient/write_roundtripper.go @@ -78,6 +78,7 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro return nil, fmt.Errorf("subresource %v is not supported by this implementation", requestInfo.Subresource) } + patchType := "" var action Action switch { case requestInfo.Verb == "create" && len(requestInfo.Subresource) == 0: @@ -90,6 +91,12 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro action = ActionApply case requestInfo.Verb == "patch" && req.Header.Get("Content-Type") == string(types.ApplyPatchType) && requestInfo.Subresource == "status": action = ActionApplyStatus + case requestInfo.Verb == "patch" && len(requestInfo.Subresource) == 0: + action = ActionPatch + patchType = req.Header.Get("Content-Type") + case requestInfo.Verb == "patch" && requestInfo.Subresource == "status": + action = ActionPatchStatus + patchType = req.Header.Get("Content-Type") case requestInfo.Verb == "delete" && len(requestInfo.Subresource) == 0: action = ActionDelete default: @@ -98,6 +105,8 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro var opts runtime.Object switch action { + case ActionPatch, ActionPatchStatus: + opts = &metav1.PatchOptions{} case ActionApply, ActionApplyStatus: opts = &metav1.PatchOptions{} case ActionUpdate, ActionUpdateStatus: @@ -126,15 +135,20 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro return nil, fmt.Errorf("failed to read body: %w", err) } } - bodyObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, bodyContent) - if err != nil { - return nil, fmt.Errorf("unable to decode body: %w", err) - } - if requestInfo.Namespace != bodyObj.(*unstructured.Unstructured).GetNamespace() { - return nil, fmt.Errorf("request namespace %q does not equal body namespace %q", requestInfo.Namespace, bodyObj.(*unstructured.Unstructured).GetNamespace()) - } - if action != ActionCreate && action != ActionDelete && requestInfo.Name != bodyObj.(*unstructured.Unstructured).GetName() { - return nil, fmt.Errorf("request name %q does not equal body name %q", requestInfo.Namespace, bodyObj.(*unstructured.Unstructured).GetNamespace()) + + var bodyObj runtime.Object + actionHasRuntimeObjectBody := action != ActionPatch && action != ActionPatchStatus + if actionHasRuntimeObjectBody { + bodyObj, err = runtime.Decode(unstructured.UnstructuredJSONScheme, bodyContent) + if err != nil { + return nil, fmt.Errorf("unable to decode body: %w", err) + } + if requestInfo.Namespace != bodyObj.(*unstructured.Unstructured).GetNamespace() { + return nil, fmt.Errorf("request namespace %q does not equal body namespace %q", requestInfo.Namespace, bodyObj.(*unstructured.Unstructured).GetNamespace()) + } + if action != ActionCreate && action != ActionDelete && requestInfo.Name != bodyObj.(*unstructured.Unstructured).GetName() { + return nil, fmt.Errorf("request name %q does not equal body name %q", requestInfo.Namespace, bodyObj.(*unstructured.Unstructured).GetNamespace()) + } } gvr := schema.GroupVersionResource{ @@ -147,28 +161,40 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro // in this case, the name isn't in the URL, it's in the body metadataName = bodyObj.(*unstructured.Unstructured).GetName() } - if action == ActionDelete { - // do this so that when we try to issue deletes later, we'll have the name we need to use. - setAnnotationFor(bodyObj.(*unstructured.Unstructured), DeletionNameAnnotation, metadataName) - } - if controllerName := ControllerInstanceNameFromContext(req.Context()); len(controllerName) > 0 { - setAnnotationFor(bodyObj.(*unstructured.Unstructured), SyntheticControllerInstanceNameAnnotation, controllerName) + + bodyOutputBytes := bodyContent + generatedName := "" + kindType := schema.GroupVersionKind{} + if actionHasRuntimeObjectBody { + bodyOutputBytes, err = yaml.Marshal(bodyObj.(*unstructured.Unstructured).Object) + if err != nil { + return nil, fmt.Errorf("unable to encode body: %w", err) + } + generatedName = bodyObj.(*unstructured.Unstructured).GetGenerateName() + kindType = bodyObj.GetObjectKind().GroupVersionKind() } - bodyYAMLBytes, err := yaml.Marshal(bodyObj.(*unstructured.Unstructured).Object) - if err != nil { - return nil, fmt.Errorf("unable to encode body: %w", err) + fieldManagerName := "" + if patchOptions, ok := opts.(*metav1.PatchOptions); ok { + fieldManagerName = patchOptions.FieldManager } serializedRequest := SerializedRequest{ - Action: action, - ResourceType: gvr, - KindType: bodyObj.GetObjectKind().GroupVersionKind(), - Namespace: requestInfo.Namespace, - Name: metadataName, - GenerateName: bodyObj.(*unstructured.Unstructured).GetGenerateName(), - Options: optionsBytes, - Body: bodyYAMLBytes, + ActionMetadata: ActionMetadata{ + Action: action, + ResourceMetadata: ResourceMetadata{ + ResourceType: gvr, + Namespace: requestInfo.Namespace, + Name: metadataName, + GenerateName: generatedName, + }, + PatchType: patchType, + FieldManager: fieldManagerName, + ControllerInstanceName: ControllerInstanceNameFromContext(req.Context()), + }, + KindType: kindType, + Options: optionsBytes, + Body: bodyOutputBytes, } // this lock also protects the access to actionTracker @@ -185,9 +211,11 @@ func (mrt *writeTrackingRoundTripper) roundTrip(req *http.Request) ([]byte, erro // returning a value that will probably not cause the wrapping client to fail, but isn't very useful. // this keeps calling code from depending on the return value. ret := &unstructured.Unstructured{Object: map[string]interface{}{}} - ret.SetGroupVersionKind(bodyObj.GetObjectKind().GroupVersionKind()) - ret.SetName(bodyObj.(*unstructured.Unstructured).GetName()) - ret.SetNamespace(bodyObj.(*unstructured.Unstructured).GetNamespace()) + ret.SetName(serializedRequest.ActionMetadata.Name) + ret.SetNamespace(serializedRequest.ActionMetadata.Namespace) + if actionHasRuntimeObjectBody { // TODO might be able to do something generally based on discovery if absolutely necessary + ret.SetGroupVersionKind(bodyObj.GetObjectKind().GroupVersionKind()) + } retBytes, err := json.Marshal(ret.Object) if err != nil { return nil, fmt.Errorf("unable to encode body: %w", err) diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/apiservice/apiservice_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/apiservice/apiservice_controller.go index bb8c47363f..78d3fe663c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/apiservice/apiservice_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/apiservice/apiservice_controller.go @@ -70,7 +70,7 @@ func NewAPIServiceController( kubeClient: kubeClient, } - return factory.New().WithSync(c.sync).ResyncEvery(10*time.Second).WithInformers( + return factory.New().WithSync(c.sync).WithControllerInstanceName(c.controllerInstanceName).ResyncEvery(10*time.Second).WithInformers( append(informers, kubeInformersForNamespaces.InformersFor(targetNamespace).Core().V1().Services().Informer(), kubeInformersForNamespaces.InformersFor(targetNamespace).Core().V1().Endpoints().Informer(), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/auditpolicy/auditpolicy_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/auditpolicy/auditpolicy_controller.go index 826d3fd6e9..9695e69da9 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/auditpolicy/auditpolicy_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/auditpolicy/auditpolicy_controller.go @@ -54,7 +54,7 @@ func NewAuditPolicyController( targetConfigMapName: targetConfigMapName, } - return factory.New().WithSync(c.sync).ResyncEvery(10*time.Second).WithInformers( + return factory.New().WithSync(c.sync).WithControllerInstanceName(c.controllerInstanceName).ResyncEvery(10*time.Second).WithInformers( configInformers.Config().V1().APIServers().Informer(), kubeInformersForTargetNamesace.Core().V1().ConfigMaps().Informer(), operatorClient.Informer(), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go index 5607995030..e6e0ba8e2f 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/controller/workload/workload.go @@ -111,6 +111,7 @@ func NewController(instanceName, operatorNamespace, targetNamespace, targetOpera } return c.WithSync(controllerRef.sync). + WithControllerInstanceName(controllerRef.controllerInstanceName). WithInformers(informers...). ToController( fmt.Sprintf("%sWorkloadController", controllerRef.controllerInstanceName), @@ -289,7 +290,9 @@ func (c *Controller) updateOperatorStatus(ctx context.Context, previousStatus *o // If the workload is up to date, then we are no longer progressing workloadAtHighestGeneration := workload.ObjectMeta.Generation == workload.Status.ObservedGeneration - workloadIsBeingUpdated := workload.Status.UpdatedReplicas < desiredReplicas + // Update is done when all pods have been updated to the latest revision + // and the deployment controller has reported NewReplicaSetAvailable + workloadIsBeingUpdated := !workloadAtHighestGeneration || !hasDeploymentProgressed(workload.Status) workloadIsBeingUpdatedTooLong, err := isUpdatingTooLong(previousStatus, *deploymentProgressingCondition.Type) if !workloadAtHighestGeneration { deploymentProgressingCondition = deploymentProgressingCondition. @@ -300,8 +303,15 @@ func (c *Controller) updateOperatorStatus(ctx context.Context, previousStatus *o deploymentProgressingCondition = deploymentProgressingCondition. WithStatus(operatorv1.ConditionTrue). WithReason("PodsUpdating"). - WithMessage(fmt.Sprintf("deployment/%s.%s: %d/%d pods have been updated to the latest generation", workload.Name, c.targetNamespace, workload.Status.UpdatedReplicas, desiredReplicas)) + WithMessage(fmt.Sprintf("deployment/%s.%s: %d/%d pods have been updated to the latest generation and %d/%d pods are available", workload.Name, c.targetNamespace, workload.Status.UpdatedReplicas, desiredReplicas, workload.Status.AvailableReplicas, desiredReplicas)) } else { + // Terminating pods don't account for any of the other status fields but + // still can exist in a state when they are accepting connections and would + // contribute to unexpected behavior when we report Progressing=False. + // The case of too many pods might occur for example if `TerminationGracePeriodSeconds` is set + // + // The workload should ensure this does not happen by using for example EnsureAtMostOnePodPerNode + // so that the old pods terminate before the new ones are started. deploymentProgressingCondition = deploymentProgressingCondition. WithStatus(operatorv1.ConditionFalse). WithReason("AsExpected") @@ -353,6 +363,17 @@ func isUpdatingTooLong(operatorStatus *operatorv1.OperatorStatus, progressingCon return progressing != nil && progressing.Status == operatorv1.ConditionTrue && time.Now().After(progressing.LastTransitionTime.Add(15*time.Minute)), nil } +// hasDeploymentProgressed returns true if the deployment reports NewReplicaSetAvailable +// via the DeploymentProgressing condition +func hasDeploymentProgressed(status appsv1.DeploymentStatus) bool { + for _, cond := range status.Conditions { + if cond.Type == appsv1.DeploymentProgressing { + return cond.Status == corev1.ConditionTrue && cond.Reason == "NewReplicaSetAvailable" + } + } + return false +} + // EnsureAtMostOnePodPerNode updates the deployment spec to prevent more than // one pod of a given replicaset from landing on a node. It accomplishes this // by adding a label on the template and updates the pod anti-affinity term to include that label. diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/OWNERS b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/OWNERS new file mode 100644 index 0000000000..8cd5c0bca3 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/OWNERS @@ -0,0 +1,4 @@ +reviewers: +- benluddy +approvers: +- benluddy diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/config_observer_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/config_observer_controller.go index b4d6f35b28..4182249986 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/config_observer_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/config_observer_controller.go @@ -122,6 +122,7 @@ func NewNestedConfigObserver( return factory.New(). ResyncEvery(time.Minute). WithSync(c.sync). + WithControllerInstanceName(c.controllerInstanceName). WithInformers(append(informers, listersToInformer(listers)...)...). ToController( "ConfigObserver", // don't change what is passed here unless you also remove the old FooDegraded condition diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/condition_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/condition_controller.go index 4cc62ad6d0..6a49889a22 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/condition_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/condition_controller.go @@ -66,6 +66,7 @@ func NewConditionController( deployer, ).ResyncEvery(time.Minute). WithSync(c.sync). + WithControllerInstanceName(c.controllerInstanceName). ToController( c.controllerInstanceName, eventRecorder.WithComponentSuffix("encryption-condition-controller"), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go index 4273c27f3b..c999f140f0 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/key_controller.go @@ -106,6 +106,7 @@ func NewKeyController( return factory.New(). WithSync(c.sync). + WithControllerInstanceName(c.controllerInstanceName). ResyncEvery(time.Minute). WithInformers( apiServerInformer.Informer(), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/migration_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/migration_controller.go index 3acbf27333..cab3e23de3 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/migration_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/migration_controller.go @@ -96,7 +96,7 @@ func NewMigrationController( preconditionsFulfilledFn: preconditionsFulfilledFn, } - return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithInformers( + return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithControllerInstanceName(c.controllerInstanceName).WithInformers( migrator, operatorClient.Informer(), kubeInformersForNamespaces.InformersFor("openshift-config-managed").Core().V1().Secrets().Informer(), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/prune_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/prune_controller.go index 4b12011a41..3078304e0b 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/prune_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/prune_controller.go @@ -70,7 +70,7 @@ func NewPruneController( secretClient: secretClient, } - return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithInformers( + return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithControllerInstanceName(c.controllerInstanceName).WithInformers( operatorClient.Informer(), kubeInformersForNamespaces.InformersFor("openshift-config-managed").Core().V1().Secrets().Informer(), apiServerConfigInformer.Informer(), // do not remove, used by the precondition checker diff --git a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/state_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/state_controller.go index 7c2b828ae8..d5dd0d66a8 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/state_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/encryption/controllers/state_controller.go @@ -73,7 +73,7 @@ func NewStateController( preconditionsFulfilledFn: preconditionsFulfilledFn, } - return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithInformers( + return factory.New().ResyncEvery(time.Minute).WithSync(c.sync).WithControllerInstanceName(c.controllerInstanceName).WithInformers( operatorClient.Informer(), kubeInformersForNamespaces.InformersFor("openshift-config-managed").Core().V1().Secrets().Informer(), apiServerConfigInformer.Informer(), // do not remove, used by the precondition checker diff --git a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder.go b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder.go index f513a90f3c..2918012ff5 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder.go @@ -2,13 +2,13 @@ package events import ( "context" + "crypto/sha256" "errors" "fmt" - "os" - "time" - "k8s.io/client-go/kubernetes" "k8s.io/klog/v2" + "k8s.io/utils/clock" + "os" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -145,11 +145,12 @@ func guessControllerReferenceForNamespace(ctx context.Context, client corev1clie } // NewRecorder returns new event recorder. -func NewRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder { +func NewRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference, clock clock.PassiveClock) Recorder { return &recorder{ eventClient: client, involvedObjectRef: involvedObjectRef, sourceComponent: sourceComponentName, + clock: clock, } } @@ -158,6 +159,7 @@ type recorder struct { eventClient corev1client.EventInterface involvedObjectRef *corev1.ObjectReference sourceComponent string + clock clock.PassiveClock // TODO: This is not the right way to pass the context, but there is no other way without breaking event interface ctx context.Context @@ -196,7 +198,7 @@ func (r *recorder) Warningf(reason, messageFmt string, args ...interface{}) { // Event emits the normal type event. func (r *recorder) Event(reason, message string) { - event := makeEvent(r.involvedObjectRef, r.sourceComponent, corev1.EventTypeNormal, reason, message) + event := makeEvent(r.clock, r.involvedObjectRef, r.sourceComponent, corev1.EventTypeNormal, reason, message) ctx := context.Background() if r.ctx != nil { ctx = r.ctx @@ -208,7 +210,7 @@ func (r *recorder) Event(reason, message string) { // Warning emits the warning type event. func (r *recorder) Warning(reason, message string) { - event := makeEvent(r.involvedObjectRef, r.sourceComponent, corev1.EventTypeWarning, reason, message) + event := makeEvent(r.clock, r.involvedObjectRef, r.sourceComponent, corev1.EventTypeWarning, reason, message) ctx := context.Background() if r.ctx != nil { ctx = r.ctx @@ -218,11 +220,12 @@ func (r *recorder) Warning(reason, message string) { } } -func makeEvent(involvedObjRef *corev1.ObjectReference, sourceComponent string, eventType, reason, message string) *corev1.Event { - currentTime := metav1.Time{Time: time.Now()} +func makeEvent(clock clock.PassiveClock, involvedObjRef *corev1.ObjectReference, sourceComponent string, eventType, reason, message string) *corev1.Event { + currentTime := metav1.Time{Time: clock.Now()} event := &corev1.Event{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%v.%x", involvedObjRef.Name, currentTime.UnixNano()), + // TODO this is always used to create a unique event. Perhaps we should hash the message to be unique enough for apply-configuration + Name: fmt.Sprintf("%v.%x.%s", involvedObjRef.Name, currentTime.UnixNano(), hashForEventNameSuffix(eventType, reason, message)), Namespace: involvedObjRef.Namespace, }, InvolvedObject: *involvedObjRef, @@ -236,3 +239,20 @@ func makeEvent(involvedObjRef *corev1.ObjectReference, sourceComponent string, e event.Source.Component = sourceComponent return event } + +func hashForEventNameSuffix(in ...string) string { + data := []byte{} + for _, curr := range in { + data = append(data, []byte(curr)...) + } + if len(data) == 0 { + return "MISSING" + } + + hash := sha256.New() + hash.Write(data) + hashBytes := hash.Sum(nil) + + // we're looking to deconflict names, not protect the crown jewels + return fmt.Sprintf("%x", hashBytes[len(hashBytes)-4:]) +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_in_memory.go b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_in_memory.go index 75efe3e192..d97be0de6c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_in_memory.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_in_memory.go @@ -3,6 +3,7 @@ package events import ( "context" "fmt" + "k8s.io/utils/clock" "sync" corev1 "k8s.io/api/core/v1" @@ -12,6 +13,7 @@ import ( type inMemoryEventRecorder struct { events []*corev1.Event source string + clock clock.PassiveClock ctx context.Context sync.Mutex } @@ -31,8 +33,12 @@ type InMemoryRecorder interface { // NewInMemoryRecorder provides event recorder that stores all events recorded in memory and allow to replay them using the Events() method. // This recorder should be only used in unit tests. -func NewInMemoryRecorder(sourceComponent string) InMemoryRecorder { - return &inMemoryEventRecorder{events: []*corev1.Event{}, source: sourceComponent} +func NewInMemoryRecorder(sourceComponent string, clock clock.PassiveClock) InMemoryRecorder { + return &inMemoryEventRecorder{ + events: []*corev1.Event{}, + source: sourceComponent, + clock: clock, + } } func (r *inMemoryEventRecorder) ComponentName() string { @@ -65,7 +71,7 @@ func (r *inMemoryEventRecorder) Events() []*corev1.Event { func (r *inMemoryEventRecorder) Event(reason, message string) { r.Lock() defer r.Unlock() - event := makeEvent(&inMemoryDummyObjectReference, r.source, corev1.EventTypeNormal, reason, message) + event := makeEvent(r.clock, &inMemoryDummyObjectReference, r.source, corev1.EventTypeNormal, reason, message) r.events = append(r.events, event) } @@ -76,7 +82,7 @@ func (r *inMemoryEventRecorder) Eventf(reason, messageFmt string, args ...interf func (r *inMemoryEventRecorder) Warning(reason, message string) { r.Lock() defer r.Unlock() - event := makeEvent(&inMemoryDummyObjectReference, r.source, corev1.EventTypeWarning, reason, message) + event := makeEvent(r.clock, &inMemoryDummyObjectReference, r.source, corev1.EventTypeWarning, reason, message) klog.Info(event.String()) r.events = append(r.events, event) } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_logging.go b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_logging.go index 90639f2d93..1906454a96 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_logging.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_logging.go @@ -3,6 +3,7 @@ package events import ( "context" "fmt" + "k8s.io/utils/clock" corev1 "k8s.io/api/core/v1" "k8s.io/klog/v2" @@ -10,6 +11,7 @@ import ( type LoggingEventRecorder struct { component string + clock clock.PassiveClock ctx context.Context } @@ -19,8 +21,11 @@ func (r *LoggingEventRecorder) WithContext(ctx context.Context) Recorder { } // NewLoggingEventRecorder provides event recorder that will log all recorded events via klog. -func NewLoggingEventRecorder(component string) Recorder { - return &LoggingEventRecorder{component: component} +func NewLoggingEventRecorder(component string, clock clock.PassiveClock) Recorder { + return &LoggingEventRecorder{ + component: component, + clock: clock, + } } func (r *LoggingEventRecorder) ComponentName() string { @@ -40,7 +45,7 @@ func (r *LoggingEventRecorder) WithComponentSuffix(suffix string) Recorder { } func (r *LoggingEventRecorder) Event(reason, message string) { - event := makeEvent(&inMemoryDummyObjectReference, "", corev1.EventTypeNormal, reason, message) + event := makeEvent(r.clock, &inMemoryDummyObjectReference, "", corev1.EventTypeNormal, reason, message) klog.Info(event.String()) } @@ -49,7 +54,7 @@ func (r *LoggingEventRecorder) Eventf(reason, messageFmt string, args ...interfa } func (r *LoggingEventRecorder) Warning(reason, message string) { - event := makeEvent(&inMemoryDummyObjectReference, "", corev1.EventTypeWarning, reason, message) + event := makeEvent(r.clock, &inMemoryDummyObjectReference, "", corev1.EventTypeWarning, reason, message) klog.Warning(event.String()) } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_upstream.go b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_upstream.go index 0e41949a77..282a9033d9 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_upstream.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/events/recorder_upstream.go @@ -3,6 +3,7 @@ package events import ( "context" "fmt" + "k8s.io/utils/clock" "strings" "sync" @@ -16,19 +17,19 @@ import ( ) // NewKubeRecorder returns new event recorder with tweaked correlator options. -func NewKubeRecorderWithOptions(client corev1client.EventInterface, options record.CorrelatorOptions, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder { +func NewKubeRecorderWithOptions(client corev1client.EventInterface, options record.CorrelatorOptions, sourceComponentName string, involvedObjectRef *corev1.ObjectReference, clock clock.PassiveClock) Recorder { return (&upstreamRecorder{ client: client, component: sourceComponentName, involvedObjectRef: involvedObjectRef, options: options, - fallbackRecorder: NewRecorder(client, sourceComponentName, involvedObjectRef), + fallbackRecorder: NewRecorder(client, sourceComponentName, involvedObjectRef, clock), }).ForComponent(sourceComponentName) } // NewKubeRecorder returns new event recorder with default correlator options. -func NewKubeRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder { - return NewKubeRecorderWithOptions(client, record.CorrelatorOptions{}, sourceComponentName, involvedObjectRef) +func NewKubeRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference, clock clock.PassiveClock) Recorder { + return NewKubeRecorderWithOptions(client, record.CorrelatorOptions{}, sourceComponentName, involvedObjectRef, clock) } // upstreamRecorder is an implementation of Recorder interface. diff --git a/vendor/github.com/openshift/library-go/pkg/operator/staleconditions/remove_stale_conditions.go b/vendor/github.com/openshift/library-go/pkg/operator/staleconditions/remove_stale_conditions.go index 7a71a0e990..3e2e270d50 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/staleconditions/remove_stale_conditions.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/staleconditions/remove_stale_conditions.go @@ -31,6 +31,7 @@ func NewRemoveStaleConditionsController( return factory.New(). ResyncEvery(time.Minute). WithSync(c.sync). + WithControllerInstanceName(c.controllerInstanceName). WithInformers(operatorClient.Informer()). ToController( c.controllerInstanceName, diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/client_mutations.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/client_mutations.go index 96747ce034..f5eee16164 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/client_mutations.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/client_mutations.go @@ -116,7 +116,7 @@ func RemoveEvents(requests []manifestclient.SerializedRequestish) []manifestclie for _, curr := range requests { metadata := curr.GetSerializedRequest().GetLookupMetadata() - if metadata.GVR.GroupResource() == coreEventGR || metadata.GVR.GroupResource() == eventGR { + if metadata.ResourceType.GroupResource() == coreEventGR || metadata.ResourceType.GroupResource() == eventGR { continue } filteredRequests = append(filteredRequests, curr) @@ -152,7 +152,7 @@ func metadataMatchesFilter(metadata manifestclient.ActionMetadata, allowedResour return true } - gr := metadata.GVR.GroupResource() + gr := metadata.ResourceType.GroupResource() if gr == coreEventGR || gr == eventGR { for _, curr := range allowedResources.EventingNamespaces { if metadata.Namespace == curr { @@ -165,8 +165,8 @@ func metadataMatchesFilter(metadata manifestclient.ActionMetadata, allowedResour if len(metadata.GenerateName) > 0 { continue } - if metadata.GVR.Group == curr.Group && - metadata.GVR.Resource == curr.Resource && + if metadata.ResourceType.Group == curr.Group && + metadata.ResourceType.Resource == curr.Resource && metadata.Namespace == curr.Namespace && metadata.Name == curr.Name { return true @@ -176,8 +176,8 @@ func metadataMatchesFilter(metadata manifestclient.ActionMetadata, allowedResour if len(metadata.Name) > 0 { continue } - if metadata.GVR.Group == curr.Group && - metadata.GVR.Resource == curr.Resource && + if metadata.ResourceType.Group == curr.Group && + metadata.ResourceType.Resource == curr.Resource && metadata.Namespace == curr.Namespace && metadata.GenerateName == curr.GeneratedName { return true diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/command.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/command.go index c48dcb6103..06d4460691 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/command.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/command.go @@ -3,11 +3,12 @@ package libraryapplyconfiguration import ( "context" "fmt" - "github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources" + "math/rand" "time" "github.com/openshift/library-go/pkg/manifestclient" "github.com/openshift/multi-operator-manager/pkg/flagtypes" + "github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources" "github.com/spf13/cobra" "github.com/spf13/pflag" "k8s.io/cli-runtime/pkg/genericiooptions" @@ -28,8 +29,7 @@ type ApplyConfigurationInput struct { // Streams is for I/O. The StdIn will usually be nil'd out. Streams genericiooptions.IOStreams - // Controllers holds an optional list of controller names to run. - // By default, all controllers are run. + // Controllers holds a list of controller names to run. Controllers []string } @@ -51,7 +51,9 @@ type applyConfigurationFlags struct { outputDirectory string // controllers hold an optional list of controller names to run. - // By default, all controllers are run. + // '*' means "all controllers are enabled by default" + // 'foo' means "enable 'foo'" + // '-foo' means "disable 'foo'" controllers []string now time.Time @@ -90,6 +92,7 @@ func newApplyConfigurationCommand(applyConfigurationFn ApplyConfigurationFunc, o if err != nil { return err } + rand.New(rand.NewSource(o.input.Clock.Now().UTC().UnixNano())) if err := o.Run(ctx); err != nil { return err } @@ -105,7 +108,7 @@ func newApplyConfigurationCommand(applyConfigurationFn ApplyConfigurationFunc, o func (f *applyConfigurationFlags) BindFlags(flags *pflag.FlagSet) { flags.StringVar(&f.inputDirectory, "input-dir", f.inputDirectory, "The directory where the resource input is stored.") flags.StringVar(&f.outputDirectory, "output-dir", f.outputDirectory, "The directory where the output is stored.") - flags.StringSliceVar(&f.controllers, "controllers", f.controllers, "An optional list of controller names to run. By default, all controllers are run.") + flags.StringSliceVar(&f.controllers, "controllers", []string{"*"}, "A list of controllers to enable. '*' enables all controllers, 'foo' enables the controller named 'foo', '-foo' disables the controller named 'foo'. Default: `*`") nowFlag := flagtypes.NewTimeValue(f.now, &f.now, []string{time.RFC3339}) flags.Var(nowFlag, "now", "The time to use time.Now during this execution.") } diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/operator_launch_helpers.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/operator_launch_helpers.go index 65ca5738a2..2bafc8d06a 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/operator_launch_helpers.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration/operator_launch_helpers.go @@ -4,7 +4,9 @@ import ( "context" "errors" "fmt" + "math/rand" "reflect" + "strings" "time" "github.com/openshift/library-go/pkg/controller/factory" @@ -26,7 +28,9 @@ type SimpleOperatorStarter struct { // ControllerRunFns is useful during a transition to coalesce the operator launching flow. ControllerRunFns []RunFunc // Controllers hold an optional list of controller names to run. - // By default, all controllers are run. + // '*' means "all controllersFromFlags are enabled by default" + // 'foo' means "enable 'foo'" + // '-foo' means "disable 'foo'" Controllers []string } @@ -60,18 +64,15 @@ func (a SimpleOperatorStarter) RunOnce(ctx context.Context) error { return fmt.Errorf("the following controllers were requested to run multiple times: %v", duplicateControllerNames) } - controllersToRunSet := sets.NewString(a.Controllers...) - if controllersToRunSet.Len() == 0 { - controllersToRunSet = knownControllersSet - } - if unknownControllersToRun := controllersToRunSet.Difference(knownControllersSet); len(unknownControllersToRun) > 0 { - return fmt.Errorf("requested unknown controllers to be run: %v, known controllers: %v", unknownControllersToRun.List(), knownControllersSet.List()) + if errs := validateControllersFromFlags(knownControllersSet, a.Controllers); len(errs) > 0 { + return errors.Join(errs...) } + shuffleNamedRunOnce(a.ControllerNamedRunOnceFns) errs := []error{} for _, controllerRunner := range a.ControllerNamedRunOnceFns { func() { - if !controllersToRunSet.Has(controllerRunner.ControllerInstanceName()) { + if !isControllerEnabled(controllerRunner.ControllerInstanceName(), a.Controllers) { return } localCtx, localCancel := context.WithTimeout(ctx, 1*time.Second) @@ -160,6 +161,30 @@ func AdaptSyncFn(eventRecorder events.Recorder, controllerName string, originalR }) } +type Syncer interface { + Sync(ctx context.Context, controllerContext factory.SyncContext) error +} + +type ControllerWithInstanceName interface { + ControllerInstanceName() string +} + +func AdaptNamedController(eventRecorder events.Recorder, controller Syncer) NamedRunOnce { + controllerWithInstanceName, ok := controller.(ControllerWithInstanceName) + if !ok { + panic(fmt.Sprintf("%T doesn't expose ControllerInstanceName() method which is required", controller)) + } + controllerInstanceName := controllerWithInstanceName.ControllerInstanceName() + if len(controllerInstanceName) == 0 { + panic(fmt.Sprintf("%T cannot return an empty ControllerInstanceName", controller)) + } + + return NewNamedRunOnce(controllerInstanceName, func(ctx context.Context) error { + syncCtx := factory.NewSyncContext("run-named-once-sync-context", eventRecorder) + return controller.Sync(ctx, syncCtx) + }) +} + type generatedInformerFactory struct { delegate GeneratedInformerFactory } @@ -200,3 +225,42 @@ func (g generatedNamespacedInformerFactory) Start(ctx context.Context) { func (g generatedNamespacedInformerFactory) WaitForCacheSync(ctx context.Context) { g.delegate.WaitForCacheSync(ctx.Done()) } + +func shuffleNamedRunOnce(controllers []NamedRunOnce) { + rand.Shuffle(len(controllers), func(i, j int) { + controllers[i], controllers[j] = controllers[j], controllers[i] + }) +} + +func isControllerEnabled(name string, controllers []string) bool { + hasStar := false + for _, ctrl := range controllers { + if ctrl == name { + return true + } + if ctrl == "-"+name { + return false + } + if ctrl == "*" { + hasStar = true + } + } + + return hasStar +} + +func validateControllersFromFlags(allKnownControllersSet sets.String, controllersToRunFromFlags []string) []error { + var errs []error + for _, initialName := range controllersToRunFromFlags { + if initialName == "*" { + continue + } + initialNameWithoutPrefix := strings.TrimPrefix(initialName, "-") + controllerName := initialNameWithoutPrefix + if !allKnownControllersSet.Has(controllerName) { + errs = append(errs, fmt.Errorf("%q is not in the list of known controllers", initialNameWithoutPrefix)) + } + } + + return errs +} diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/prune_mustgather.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/prune_mustgather.go index 9553e37785..922bbed234 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/prune_mustgather.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/prune_mustgather.go @@ -17,6 +17,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" ) @@ -56,23 +57,34 @@ func GetRequiredInputResourcesFromMustGather(ctx context.Context, inputResources } func NewDynamicClientFromMustGather(mustGatherDir string) (dynamic.Interface, error) { - roundTripper := manifestclient.NewRoundTripper(mustGatherDir) - httpClient := &http.Client{ - Transport: roundTripper, - } - + httpClient := newHTTPClientFromMustGather(mustGatherDir) dynamicClient, err := dynamic.NewForConfigAndClient(&rest.Config{}, httpClient) if err != nil { return nil, fmt.Errorf("failure creating dynamicClient for NewDynamicClientFromMustGather: %w", err) } - return dynamicClient, nil } +func NewDiscoveryClientFromMustGather(mustGatherDir string) (discovery.AggregatedDiscoveryInterface, error) { + httpClient := newHTTPClientFromMustGather(mustGatherDir) + discoveryClient, err := discovery.NewDiscoveryClientForConfigAndClient(manifestclient.RecommendedRESTConfig(), httpClient) + if err != nil { + return nil, fmt.Errorf("failure creating discoveryClient for NewDiscoveryClientFromMustGather: %w", err) + } + return discoveryClient, nil +} + +func newHTTPClientFromMustGather(mustGatherDir string) *http.Client { + roundTripper := manifestclient.NewRoundTripper(mustGatherDir) + return &http.Client{ + Transport: roundTripper, + } +} + var builder = gval.Full(jsonpath.Language()) func GetRequiredInputResourcesForResourceList(ctx context.Context, resourceList ResourceList, dynamicClient dynamic.Interface) ([]*Resource, error) { - instances := []*Resource{} + instances := NewUniqueResourceSet() errs := []error{} for _, currResource := range resourceList.ExactResources { @@ -84,15 +96,26 @@ func GetRequiredInputResourcesForResourceList(ctx context.Context, resourceList errs = append(errs, err) continue } - instances = append(instances, resourceInstance) + instances.Insert(resourceInstance) + } + + for _, currResource := range resourceList.LabelSelectedResources { + resourceList, err := getResourcesByLabelSelector(ctx, dynamicClient, currResource) + if apierrors.IsNotFound(err) { + continue + } + if err != nil { + errs = append(errs, err) + continue + } + instances.Insert(resourceList...) } path := field.NewPath(".") - for i, currResourceRef := range resourceList.ResourceReference { + for i, currResourceRef := range resourceList.ResourceReferences { currFieldPath := path.Child("resourceReference").Index(i) - referringGVR := schema.GroupVersionResource{Group: currResourceRef.ReferringResource.Group, Version: currResourceRef.ReferringResource.Version, Resource: currResourceRef.ReferringResource.Resource} - referringResourceInstance, err := dynamicClient.Resource(referringGVR).Namespace(currResourceRef.ReferringResource.Namespace).Get(ctx, currResourceRef.ReferringResource.Name, metav1.GetOptions{}) + referringResourceInstance, err := getExactResource(ctx, dynamicClient, currResourceRef.ReferringResource) if apierrors.IsNotFound(err) { continue } @@ -100,6 +123,7 @@ func GetRequiredInputResourcesForResourceList(ctx context.Context, resourceList errs = append(errs, fmt.Errorf("failed reading referringResource [%v] %#v: %w", currFieldPath, currResourceRef.ReferringResource, err)) continue } + instances.Insert(referringResourceInstance) switch { case currResourceRef.ImplicitNamespacedReference != nil: @@ -109,7 +133,7 @@ func GetRequiredInputResourcesForResourceList(ctx context.Context, resourceList continue } - results, err := fieldPathEvaluator(ctx, referringResourceInstance.UnstructuredContent()) + results, err := fieldPathEvaluator(ctx, referringResourceInstance.Content.UnstructuredContent()) if err != nil { errs = append(errs, fmt.Errorf("unexpected error finding value for %v from %v with jsonPath: %w", currFieldPath, "TODO", err)) continue @@ -145,12 +169,12 @@ func GetRequiredInputResourcesForResourceList(ctx context.Context, resourceList continue } - instances = append(instances, resourceInstance) + instances.Insert(resourceInstance) } } } - return instances, errors.Join(errs...) + return instances.List(), errors.Join(errs...) } func getExactResource(ctx context.Context, dynamicClient dynamic.Interface, resourceReference ExactResourceID) (*Resource, error) { @@ -167,6 +191,40 @@ func getExactResource(ctx context.Context, dynamicClient dynamic.Interface, reso return resourceInstance, nil } +func getResourcesByLabelSelector(ctx context.Context, dynamicClient dynamic.Interface, labelSelectedResource LabelSelectedResource) ([]*Resource, error) { + gvr := schema.GroupVersionResource{ + Group: labelSelectedResource.Group, + Version: labelSelectedResource.Version, + Resource: labelSelectedResource.Resource, + } + + selector, err := metav1.LabelSelectorAsSelector(&labelSelectedResource.LabelSelector) + if err != nil { + return nil, err + } + + namespace := labelSelectedResource.Namespace + if namespace == "" { + namespace = metav1.NamespaceAll + } + + unstructuredList, err := dynamicClient.Resource(gvr).Namespace(namespace).List(ctx, metav1.ListOptions{LabelSelector: selector.String()}) + if err != nil { + return nil, fmt.Errorf("failed getting list of resources with labelSelector %q: %w", selector, err) + } + + var resources []*Resource + for _, item := range unstructuredList.Items { + resourceInstance := &Resource{ + ResourceType: gvr, + Content: &item, + } + resources = append(resources, resourceInstance) + } + + return resources, nil +} + func IdentifierForExactResourceRef(resourceReference *ExactResourceID) string { return fmt.Sprintf("%s.%s.%s/%s[%s]", resourceReference.Resource, resourceReference.Version, resourceReference.Group, resourceReference.Name, resourceReference.Namespace) } @@ -234,8 +292,9 @@ func unstructuredToMustGatherFormat(in []*Resource) ([]*Resource, error) { listAsUnstructured := &unstructured.Unstructured{Object: list.UnstructuredContent()} resourceType := groupKindToResource[mustGatherKey.gk] ret = append(ret, &Resource{ - Filename: path.Join(namespacedString, mustGatherKey.namespace, groupString, fmt.Sprintf("%s.yaml", resourceType.Resource)), - Content: listAsUnstructured, + Filename: path.Join(namespacedString, mustGatherKey.namespace, groupString, fmt.Sprintf("%s.yaml", resourceType.Resource)), + Content: listAsUnstructured, + ResourceType: resourceType, }) } diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/resource.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/resource.go index 26a6b74088..d40811331d 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/resource.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/resource.go @@ -8,12 +8,15 @@ import ( "path" "path/filepath" "reflect" - "sigs.k8s.io/yaml" "strings" + "sigs.k8s.io/yaml" + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" ) // TODO this is a good target to move to library-go so we all agree how to reference these. @@ -23,10 +26,29 @@ type Resource struct { Content *unstructured.Unstructured } +func (r Resource) ID() string { + name := r.Content.GetName() + namespace := r.Content.GetNamespace() + if namespace == "" { + namespace = "_cluster_scoped_resource_" + } + return fmt.Sprintf("%s/%s/%s/%s", r.ResourceType.Group, r.ResourceType.Resource, namespace, name) +} + func LenientResourcesFromDirRecursive(location string) ([]*Resource, error) { + discoveryClient, err := NewDiscoveryClientFromMustGather(location) + if err != nil { + return nil, err + } + + _, apiResourceList, _, err := discoveryClient.GroupsAndMaybeResources() + if err != nil { + return nil, fmt.Errorf("failed to get api resource list: %w", err) + } + currResourceList := []*Resource{} errs := []error{} - err := filepath.WalkDir(location, func(currLocation string, currFile fs.DirEntry, err error) error { + err = filepath.WalkDir(location, func(currLocation string, currFile fs.DirEntry, err error) error { if err != nil { errs = append(errs, err) } @@ -37,11 +59,11 @@ func LenientResourcesFromDirRecursive(location string) ([]*Resource, error) { if !strings.HasSuffix(currFile.Name(), ".yaml") && !strings.HasSuffix(currFile.Name(), ".json") { return nil } - currResource, err := ResourceFromFile(currLocation, location) + currResource, err := ResourcesFromFile(apiResourceList, currLocation, location) if err != nil { return fmt.Errorf("error deserializing %q: %w", currLocation, err) } - currResourceList = append(currResourceList, currResource) + currResourceList = append(currResourceList, currResource...) return nil }) @@ -52,7 +74,37 @@ func LenientResourcesFromDirRecursive(location string) ([]*Resource, error) { return currResourceList, errors.Join(errs...) } -func ResourceFromFile(location, fileTrimPrefix string) (*Resource, error) { +func findGVR(resources map[schema.GroupVersion]*metav1.APIResourceList, gvk schema.GroupVersionKind) (*schema.GroupVersionResource, error) { + apiResourceList, ok := resources[gvk.GroupVersion()] + if !ok { + return nil, fmt.Errorf("failed to find api resource list for gvk %s", gvk) + } + + var matches []*schema.GroupVersionResource + for _, apiResource := range apiResourceList.APIResources { + if strings.Contains(apiResource.Name, "/") { + // Skip subresources + continue + } + if apiResource.Kind == gvk.Kind { + matches = append(matches, &schema.GroupVersionResource{ + Group: gvk.Group, + Version: gvk.Version, + Resource: apiResource.Name, + }) + } + } + switch len(matches) { + case 1: + return matches[0], nil + case 0: + return nil, fmt.Errorf("failed to find resource for gvk %s", gvk) + default: + return nil, fmt.Errorf("multiple resources found for gvk %v", matches) + } +} + +func ResourcesFromFile(apiResourceList map[schema.GroupVersion]*metav1.APIResourceList, location, fileTrimPrefix string) ([]*Resource, error) { content, err := os.ReadFile(location) if err != nil { return nil, fmt.Errorf("unable to read %q: %w", location, err) @@ -73,11 +125,44 @@ func ResourceFromFile(location, fileTrimPrefix string) (*Resource, error) { retFilename := strings.TrimPrefix(location, fileTrimPrefix) retFilename = strings.TrimPrefix(retFilename, "/") + retContent := ret.(*unstructured.Unstructured) - return &Resource{ + resource := &Resource{ Filename: retFilename, - Content: ret.(*unstructured.Unstructured), - }, nil + Content: retContent, + } + + // Short-circuit if the file contains a single resource + if !resource.Content.IsList() { + gvk := retContent.GroupVersionKind() + gvr, err := findGVR(apiResourceList, gvk) + if err != nil { + return nil, fmt.Errorf("failed to find gvr: %w", err) + } + resource.ResourceType = *gvr + return []*Resource{resource}, nil + } + + // Unpack if the file contains a list of resources + list, err := resource.Content.ToList() + if err != nil { + return nil, fmt.Errorf("unable to convert resource content to list: %w", err) + } + + resources := make([]*Resource, 0, len(list.Items)) + for _, item := range list.Items { + gvr, err := findGVR(apiResourceList, item.GroupVersionKind()) + if err != nil { + return nil, fmt.Errorf("failed to find gvr: %w", err) + } + resources = append(resources, &Resource{ + Filename: resource.Filename, + Content: &item, + ResourceType: *gvr, + }) + } + + return resources, nil } func IdentifyResource(in *Resource) string { @@ -146,3 +231,34 @@ func findResource(in []*Resource, filename string) *Resource { return nil } + +func NewUniqueResourceSet(resources ...*Resource) *UniqueResourceSet { + u := &UniqueResourceSet{ + seen: sets.New[string](), + resources: []*Resource{}, + } + u.Insert(resources...) + return u +} + +type UniqueResourceSet struct { + seen sets.Set[string] + resources []*Resource +} + +func (u *UniqueResourceSet) Insert(resources ...*Resource) { + for _, resource := range resources { + if resource == nil { + continue + } + if u.seen.Has(resource.ID()) { + continue + } + u.resources = append(u.resources, resource) + u.seen.Insert(resource.ID()) + } +} + +func (u *UniqueResourceSet) List() []*Resource { + return u.resources +} diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/types.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/types.go index d0a6057239..c9ce14e26f 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/types.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/types.go @@ -1,5 +1,9 @@ package libraryinputresources +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + // InputResources contains the items that an operator needs to make a decision about what needs to be create, // modified, or removed. type InputResources struct { @@ -14,11 +18,22 @@ type InputResources struct { type ResourceList struct { ExactResources []ExactResourceID `json:"exactResources,omitempty"` - GeneratedNameResources []GeneratedResourceID `json:"generatedNameResource,omitempty"` + GeneratedNameResources []GeneratedResourceID `json:"generatedNameResources,omitempty"` + + LabelSelectedResources []LabelSelectedResource `json:"labelSelectedResources,omitempty"` // use resourceReferences when one resource (apiserver.config.openshift.io/cluster) refers to another resource // like a secret (.spec.servingCerts.namedCertificates[*].servingCertificates.name). - ResourceReference []ResourceReference `json:"resourceReferences,omitempty"` + ResourceReferences []ResourceReference `json:"resourceReferences,omitempty"` +} + +type LabelSelectedResource struct { + InputResourceTypeIdentifier `json:",inline"` + + Namespace string `json:"namespace,omitempty"` + + // validation prevents setting matchExpressions + LabelSelector metav1.LabelSelector `json:"labelSelector"` } type OperandResourceList struct { diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/validation.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/validation.go index 8e6ef44a5f..7697afcfd6 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/validation.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryinputresources/validation.go @@ -27,7 +27,10 @@ func validateResourceList(path *field.Path, obj ResourceList) []error { for i, curr := range obj.ExactResources { errs = append(errs, validateExactResourceID(path.Child("exactResources").Index(i), curr)...) } - for i, curr := range obj.ResourceReference { + for i, curr := range obj.LabelSelectedResources { + errs = append(errs, validateLabelSelectedResources(path.Child("labelSelectedResources").Index(i), curr)...) + } + for i, curr := range obj.ResourceReferences { errs = append(errs, validateResourceReference(path.Child("resourceReferences").Index(i), curr)...) } @@ -45,6 +48,16 @@ func validateExactResourceID(path *field.Path, obj ExactResourceID) []error { return errs } +func validateLabelSelectedResources(path *field.Path, obj LabelSelectedResource) []error { + errs := []error{} + + errs = append(errs, validateInputResourceTypeIdentifier(path, obj.InputResourceTypeIdentifier)...) + if len(obj.LabelSelector.MatchExpressions) > 0 { + errs = append(errs, field.Forbidden(path.Child("matchExpressions"), "not supported")) + } + return errs +} + func validateInputResourceTypeIdentifier(path *field.Path, obj InputResourceTypeIdentifier) []error { errs := []error{} diff --git a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources/types.go b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources/types.go index cfd884f66f..54a3c04423 100644 --- a/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources/types.go +++ b/vendor/github.com/openshift/multi-operator-manager/pkg/library/libraryoutputresources/types.go @@ -21,10 +21,10 @@ type ResourceList struct { // exactResources are lists of exact names that are mutated ExactResources []ExactResourceID `json:"exactResources,omitempty"` - // generatedNameResource are lists of generatedNames that are mutated. + // generatedNameResources are lists of generatedNames that are mutated. // These are also honored on non-creates, via prefix matching, but *only* on resource with generatedNames. // This is not a cheat code for prefix matching. - GeneratedNameResources []GeneratedResourceID `json:"generatedNameResource,omitempty"` + GeneratedNameResources []GeneratedResourceID `json:"generatedNameResources,omitempty"` // eventingNamespaces holds a list of namespaces that the operator can output event into. // This allows redirection of events to a particular cluster on a per-namespace level. diff --git a/vendor/modules.txt b/vendor/modules.txt index 9475041407..fba9391abd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -175,7 +175,7 @@ github.com/modern-go/reflect2 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg -# github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f +# github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2 ## explicit; go 1.22.0 github.com/openshift/api github.com/openshift/api/annotations @@ -315,7 +315,7 @@ github.com/openshift/client-go/user/applyconfigurations/internal github.com/openshift/client-go/user/applyconfigurations/user/v1 github.com/openshift/client-go/user/clientset/versioned/scheme github.com/openshift/client-go/user/clientset/versioned/typed/user/v1 -# github.com/openshift/library-go v0.0.0-20241106000323-9fcf3125a28e +# github.com/openshift/library-go v0.0.0-20241126120118-cc54dd38ae04 ## explicit; go 1.22.0 github.com/openshift/library-go/pkg/apiserver/jsonpatch github.com/openshift/library-go/pkg/apps/deployment @@ -387,7 +387,7 @@ github.com/openshift/library-go/pkg/route/routeapihelpers github.com/openshift/library-go/pkg/serviceability github.com/openshift/library-go/test/library github.com/openshift/library-go/test/library/encryption -# github.com/openshift/multi-operator-manager v0.0.0-20241101153049-fcf403de1051 +# github.com/openshift/multi-operator-manager v0.0.0-20241121231342-ecea9d7ffa35 ## explicit; go 1.22.0 github.com/openshift/multi-operator-manager/pkg/flagtypes github.com/openshift/multi-operator-manager/pkg/library/libraryapplyconfiguration