diff --git a/Makefile b/Makefile index 31b0bcca3e..9ed405aa60 100644 --- a/Makefile +++ b/Makefile @@ -220,7 +220,9 @@ pao-functests-updating-profile: cluster-label-worker-cnf pao-functests-update-on pao-functests-update-only: $(BINDATA) @echo "Cluster Version" hack/show-cluster-version.sh - hack/run-test.sh -t "test/e2e/performanceprofile/functests/0_config test/e2e/performanceprofile/functests/2_performance_update test/e2e/performanceprofile/functests/3_performance_status test/e2e/performanceprofile/functests/7_performance_kubelet_node test/e2e/performanceprofile/functests/9_reboot test/e2e/performanceprofile/functests/13_llc" -p "-v -r --fail-fast --flake-attempts=2 --timeout=5h --junit-report=report.xml" -m "Running Functional Tests" + hack/run-test.sh -t "test/e2e/performanceprofile/functests/0_config test/e2e/performanceprofile/functests/3_performance_status " -p "-v -r --fail-fast --flake-attempts=2 --timeout=5h --junit-report=report.xml" -m "Running Functional Tests" + +# hack/run-test.sh -t "test/e2e/performanceprofile/functests/0_config test/e2e/performanceprofile/functests/2_performance_update test/e2e/performanceprofile/functests/3_performance_status test/e2e/performanceprofile/functests/7_performance_kubelet_node test/e2e/performanceprofile/functests/9_reboot test/e2e/performanceprofile/functests/13_llc" -p "-v -r --fail-fast --flake-attempts=2 --timeout=5h --junit-report=report.xml" -m "Running Functional Tests" .PHONY: pao-functests-update-only-hypershift pao-functests-update-only-hypershift: $(BINDATA) diff --git a/manifests/20-profile.crd.yaml b/manifests/20-profile.crd.yaml index 8dbad67665..e3e1f64fa7 100644 --- a/manifests/20-profile.crd.yaml +++ b/manifests/20-profile.crd.yaml @@ -78,8 +78,12 @@ spec: type: object properties: reapply_sysctl: - description: 'turn reapply_sysctl functionality on/off for the TuneD daemon: true/false' + description: 'turn reapply_sysctl functionality on/off for the TuneD daemon: true/false (default is true)' type: boolean + startup_udev_settle_wait: + description: 'configure startup_udev_settle_wait timeout functionality for the TuneD daemon: unsigned integer (default is 20)' + type: integer + format: int64 tunedProfile: description: TuneD profile to apply type: string diff --git a/manifests/20-tuned.crd.yaml b/manifests/20-tuned.crd.yaml index 071bf90253..0d7d0f3dd2 100644 --- a/manifests/20-tuned.crd.yaml +++ b/manifests/20-tuned.crd.yaml @@ -144,8 +144,14 @@ spec: properties: reapply_sysctl: description: 'turn reapply_sysctl functionality on/off - for the TuneD daemon: true/false' + for the TuneD daemon: true/false (default is true)' type: boolean + startup_udev_settle_wait: + description: 'configure startup_udev_settle_wait timeout + functionality for the TuneD daemon: unsigned integer + (default is 20)' + format: int64 + type: integer type: object verbosity: description: klog logging verbosity diff --git a/pkg/apis/tuned/v1/tuned_types.go b/pkg/apis/tuned/v1/tuned_types.go index 38a4ca7fea..cb8c6cb34f 100644 --- a/pkg/apis/tuned/v1/tuned_types.go +++ b/pkg/apis/tuned/v1/tuned_types.go @@ -128,9 +128,12 @@ type OperandConfig struct { // Global configuration for the TuneD daemon as defined in tuned-main.conf type TuneDConfig struct { - // turn reapply_sysctl functionality on/off for the TuneD daemon: true/false + // turn reapply_sysctl functionality on/off for the TuneD daemon: true/false (default is true) // +optional ReapplySysctl *bool `json:"reapply_sysctl"` + // configure startup_udev_settle_wait timeout functionality for the TuneD daemon: unsigned integer (default is 20) + // +optional + StartupUdevSettleWait *uint64 `json:"startup_udev_settle_wait"` } // TunedStatus is the status for a Tuned resource. diff --git a/pkg/apis/tuned/v1/zz_generated.deepcopy.go b/pkg/apis/tuned/v1/zz_generated.deepcopy.go index 900ec6ca59..d74b6b6e73 100644 --- a/pkg/apis/tuned/v1/zz_generated.deepcopy.go +++ b/pkg/apis/tuned/v1/zz_generated.deepcopy.go @@ -191,6 +191,11 @@ func (in *TuneDConfig) DeepCopyInto(out *TuneDConfig) { *out = new(bool) **out = **in } + if in.StartupUdevSettleWait != nil { + in, out := &in.StartupUdevSettleWait, &out.StartupUdevSettleWait + *out = new(uint64) + **out = **in + } return } diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go index 28619f2694..98be2e3889 100644 --- a/pkg/generated/clientset/versioned/clientset.go +++ b/pkg/generated/clientset/versioned/clientset.go @@ -18,8 +18,8 @@ limitations under the License. package versioned import ( - "fmt" - "net/http" + fmt "fmt" + http "net/http" tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/typed/tuned/v1" discovery "k8s.io/client-go/discovery" diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_profile.go b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_profile.go index 59957e92c0..5cf9f4d97c 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_profile.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_profile.go @@ -18,129 +18,30 @@ limitations under the License. package fake import ( - "context" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/typed/tuned/v1" + gentype "k8s.io/client-go/gentype" ) -// FakeProfiles implements ProfileInterface -type FakeProfiles struct { +// fakeProfiles implements ProfileInterface +type fakeProfiles struct { + *gentype.FakeClientWithList[*v1.Profile, *v1.ProfileList] Fake *FakeTunedV1 - ns string -} - -var profilesResource = v1.SchemeGroupVersion.WithResource("profiles") - -var profilesKind = v1.SchemeGroupVersion.WithKind("Profile") - -// Get takes name of the profile, and returns the corresponding profile object, and an error if there is any. -func (c *FakeProfiles) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Profile, err error) { - emptyResult := &v1.Profile{} - obj, err := c.Fake. - Invokes(testing.NewGetActionWithOptions(profilesResource, c.ns, name, options), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Profile), err -} - -// List takes label and field selectors, and returns the list of Profiles that match those selectors. -func (c *FakeProfiles) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ProfileList, err error) { - emptyResult := &v1.ProfileList{} - obj, err := c.Fake. - Invokes(testing.NewListActionWithOptions(profilesResource, profilesKind, c.ns, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1.ProfileList{ListMeta: obj.(*v1.ProfileList).ListMeta} - for _, item := range obj.(*v1.ProfileList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested profiles. -func (c *FakeProfiles) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchActionWithOptions(profilesResource, c.ns, opts)) - -} - -// Create takes the representation of a profile and creates it. Returns the server's representation of the profile, and an error, if there is any. -func (c *FakeProfiles) Create(ctx context.Context, profile *v1.Profile, opts metav1.CreateOptions) (result *v1.Profile, err error) { - emptyResult := &v1.Profile{} - obj, err := c.Fake. - Invokes(testing.NewCreateActionWithOptions(profilesResource, c.ns, profile, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Profile), err -} - -// Update takes the representation of a profile and updates it. Returns the server's representation of the profile, and an error, if there is any. -func (c *FakeProfiles) Update(ctx context.Context, profile *v1.Profile, opts metav1.UpdateOptions) (result *v1.Profile, err error) { - emptyResult := &v1.Profile{} - obj, err := c.Fake. - Invokes(testing.NewUpdateActionWithOptions(profilesResource, c.ns, profile, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Profile), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeProfiles) UpdateStatus(ctx context.Context, profile *v1.Profile, opts metav1.UpdateOptions) (result *v1.Profile, err error) { - emptyResult := &v1.Profile{} - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceActionWithOptions(profilesResource, "status", c.ns, profile, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Profile), err -} - -// Delete takes name of the profile and deletes it. Returns an error if one occurs. -func (c *FakeProfiles) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(profilesResource, c.ns, name, opts), &v1.Profile{}) - - return err } -// DeleteCollection deletes a collection of objects. -func (c *FakeProfiles) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { - action := testing.NewDeleteCollectionActionWithOptions(profilesResource, c.ns, opts, listOpts) - - _, err := c.Fake.Invokes(action, &v1.ProfileList{}) - return err -} - -// Patch applies the patch and returns the patched profile. -func (c *FakeProfiles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Profile, err error) { - emptyResult := &v1.Profile{} - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceActionWithOptions(profilesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) - - if obj == nil { - return emptyResult, err +func newFakeProfiles(fake *FakeTunedV1, namespace string) tunedv1.ProfileInterface { + return &fakeProfiles{ + gentype.NewFakeClientWithList[*v1.Profile, *v1.ProfileList]( + fake.Fake, + namespace, + v1.SchemeGroupVersion.WithResource("profiles"), + v1.SchemeGroupVersion.WithKind("Profile"), + func() *v1.Profile { return &v1.Profile{} }, + func() *v1.ProfileList { return &v1.ProfileList{} }, + func(dst, src *v1.ProfileList) { dst.ListMeta = src.ListMeta }, + func(list *v1.ProfileList) []*v1.Profile { return gentype.ToPointerSlice(list.Items) }, + func(list *v1.ProfileList, items []*v1.Profile) { list.Items = gentype.FromPointerSlice(items) }, + ), + fake, } - return obj.(*v1.Profile), err } diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned.go b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned.go index e204501b60..b75df8ac32 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned.go @@ -18,129 +18,30 @@ limitations under the License. package fake import ( - "context" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/typed/tuned/v1" + gentype "k8s.io/client-go/gentype" ) -// FakeTuneds implements TunedInterface -type FakeTuneds struct { +// fakeTuneds implements TunedInterface +type fakeTuneds struct { + *gentype.FakeClientWithList[*v1.Tuned, *v1.TunedList] Fake *FakeTunedV1 - ns string -} - -var tunedsResource = v1.SchemeGroupVersion.WithResource("tuneds") - -var tunedsKind = v1.SchemeGroupVersion.WithKind("Tuned") - -// Get takes name of the tuned, and returns the corresponding tuned object, and an error if there is any. -func (c *FakeTuneds) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Tuned, err error) { - emptyResult := &v1.Tuned{} - obj, err := c.Fake. - Invokes(testing.NewGetActionWithOptions(tunedsResource, c.ns, name, options), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Tuned), err -} - -// List takes label and field selectors, and returns the list of Tuneds that match those selectors. -func (c *FakeTuneds) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TunedList, err error) { - emptyResult := &v1.TunedList{} - obj, err := c.Fake. - Invokes(testing.NewListActionWithOptions(tunedsResource, tunedsKind, c.ns, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1.TunedList{ListMeta: obj.(*v1.TunedList).ListMeta} - for _, item := range obj.(*v1.TunedList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested tuneds. -func (c *FakeTuneds) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchActionWithOptions(tunedsResource, c.ns, opts)) - -} - -// Create takes the representation of a tuned and creates it. Returns the server's representation of the tuned, and an error, if there is any. -func (c *FakeTuneds) Create(ctx context.Context, tuned *v1.Tuned, opts metav1.CreateOptions) (result *v1.Tuned, err error) { - emptyResult := &v1.Tuned{} - obj, err := c.Fake. - Invokes(testing.NewCreateActionWithOptions(tunedsResource, c.ns, tuned, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Tuned), err -} - -// Update takes the representation of a tuned and updates it. Returns the server's representation of the tuned, and an error, if there is any. -func (c *FakeTuneds) Update(ctx context.Context, tuned *v1.Tuned, opts metav1.UpdateOptions) (result *v1.Tuned, err error) { - emptyResult := &v1.Tuned{} - obj, err := c.Fake. - Invokes(testing.NewUpdateActionWithOptions(tunedsResource, c.ns, tuned, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Tuned), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTuneds) UpdateStatus(ctx context.Context, tuned *v1.Tuned, opts metav1.UpdateOptions) (result *v1.Tuned, err error) { - emptyResult := &v1.Tuned{} - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceActionWithOptions(tunedsResource, "status", c.ns, tuned, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1.Tuned), err -} - -// Delete takes name of the tuned and deletes it. Returns an error if one occurs. -func (c *FakeTuneds) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(tunedsResource, c.ns, name, opts), &v1.Tuned{}) - - return err } -// DeleteCollection deletes a collection of objects. -func (c *FakeTuneds) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { - action := testing.NewDeleteCollectionActionWithOptions(tunedsResource, c.ns, opts, listOpts) - - _, err := c.Fake.Invokes(action, &v1.TunedList{}) - return err -} - -// Patch applies the patch and returns the patched tuned. -func (c *FakeTuneds) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Tuned, err error) { - emptyResult := &v1.Tuned{} - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceActionWithOptions(tunedsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) - - if obj == nil { - return emptyResult, err +func newFakeTuneds(fake *FakeTunedV1, namespace string) tunedv1.TunedInterface { + return &fakeTuneds{ + gentype.NewFakeClientWithList[*v1.Tuned, *v1.TunedList]( + fake.Fake, + namespace, + v1.SchemeGroupVersion.WithResource("tuneds"), + v1.SchemeGroupVersion.WithKind("Tuned"), + func() *v1.Tuned { return &v1.Tuned{} }, + func() *v1.TunedList { return &v1.TunedList{} }, + func(dst, src *v1.TunedList) { dst.ListMeta = src.ListMeta }, + func(list *v1.TunedList) []*v1.Tuned { return gentype.ToPointerSlice(list.Items) }, + func(list *v1.TunedList, items []*v1.Tuned) { list.Items = gentype.FromPointerSlice(items) }, + ), + fake, } - return obj.(*v1.Tuned), err } diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned_client.go b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned_client.go index 68d8ba2a24..d6f5da28e8 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned_client.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/fake/fake_tuned_client.go @@ -28,11 +28,11 @@ type FakeTunedV1 struct { } func (c *FakeTunedV1) Profiles(namespace string) v1.ProfileInterface { - return &FakeProfiles{c, namespace} + return newFakeProfiles(c, namespace) } func (c *FakeTunedV1) Tuneds(namespace string) v1.TunedInterface { - return &FakeTuneds{c, namespace} + return newFakeTuneds(c, namespace) } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/profile.go b/pkg/generated/clientset/versioned/typed/tuned/v1/profile.go index 269b30d715..e26855c27f 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/profile.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/profile.go @@ -18,9 +18,9 @@ limitations under the License. package v1 import ( - "context" + context "context" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" scheme "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -36,33 +36,34 @@ type ProfilesGetter interface { // ProfileInterface has methods to work with Profile resources. type ProfileInterface interface { - Create(ctx context.Context, profile *v1.Profile, opts metav1.CreateOptions) (*v1.Profile, error) - Update(ctx context.Context, profile *v1.Profile, opts metav1.UpdateOptions) (*v1.Profile, error) + Create(ctx context.Context, profile *tunedv1.Profile, opts metav1.CreateOptions) (*tunedv1.Profile, error) + Update(ctx context.Context, profile *tunedv1.Profile, opts metav1.UpdateOptions) (*tunedv1.Profile, error) // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - UpdateStatus(ctx context.Context, profile *v1.Profile, opts metav1.UpdateOptions) (*v1.Profile, error) + UpdateStatus(ctx context.Context, profile *tunedv1.Profile, opts metav1.UpdateOptions) (*tunedv1.Profile, error) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error - Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Profile, error) - List(ctx context.Context, opts metav1.ListOptions) (*v1.ProfileList, error) + Get(ctx context.Context, name string, opts metav1.GetOptions) (*tunedv1.Profile, error) + List(ctx context.Context, opts metav1.ListOptions) (*tunedv1.ProfileList, error) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Profile, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *tunedv1.Profile, err error) ProfileExpansion } // profiles implements ProfileInterface type profiles struct { - *gentype.ClientWithList[*v1.Profile, *v1.ProfileList] + *gentype.ClientWithList[*tunedv1.Profile, *tunedv1.ProfileList] } // newProfiles returns a Profiles func newProfiles(c *TunedV1Client, namespace string) *profiles { return &profiles{ - gentype.NewClientWithList[*v1.Profile, *v1.ProfileList]( + gentype.NewClientWithList[*tunedv1.Profile, *tunedv1.ProfileList]( "profiles", c.RESTClient(), scheme.ParameterCodec, namespace, - func() *v1.Profile { return &v1.Profile{} }, - func() *v1.ProfileList { return &v1.ProfileList{} }), + func() *tunedv1.Profile { return &tunedv1.Profile{} }, + func() *tunedv1.ProfileList { return &tunedv1.ProfileList{} }, + ), } } diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/tuned.go b/pkg/generated/clientset/versioned/typed/tuned/v1/tuned.go index fe1add0833..b05246ff50 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/tuned.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/tuned.go @@ -18,9 +18,9 @@ limitations under the License. package v1 import ( - "context" + context "context" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" scheme "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" @@ -36,33 +36,34 @@ type TunedsGetter interface { // TunedInterface has methods to work with Tuned resources. type TunedInterface interface { - Create(ctx context.Context, tuned *v1.Tuned, opts metav1.CreateOptions) (*v1.Tuned, error) - Update(ctx context.Context, tuned *v1.Tuned, opts metav1.UpdateOptions) (*v1.Tuned, error) + Create(ctx context.Context, tuned *tunedv1.Tuned, opts metav1.CreateOptions) (*tunedv1.Tuned, error) + Update(ctx context.Context, tuned *tunedv1.Tuned, opts metav1.UpdateOptions) (*tunedv1.Tuned, error) // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - UpdateStatus(ctx context.Context, tuned *v1.Tuned, opts metav1.UpdateOptions) (*v1.Tuned, error) + UpdateStatus(ctx context.Context, tuned *tunedv1.Tuned, opts metav1.UpdateOptions) (*tunedv1.Tuned, error) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error - Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Tuned, error) - List(ctx context.Context, opts metav1.ListOptions) (*v1.TunedList, error) + Get(ctx context.Context, name string, opts metav1.GetOptions) (*tunedv1.Tuned, error) + List(ctx context.Context, opts metav1.ListOptions) (*tunedv1.TunedList, error) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Tuned, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *tunedv1.Tuned, err error) TunedExpansion } // tuneds implements TunedInterface type tuneds struct { - *gentype.ClientWithList[*v1.Tuned, *v1.TunedList] + *gentype.ClientWithList[*tunedv1.Tuned, *tunedv1.TunedList] } // newTuneds returns a Tuneds func newTuneds(c *TunedV1Client, namespace string) *tuneds { return &tuneds{ - gentype.NewClientWithList[*v1.Tuned, *v1.TunedList]( + gentype.NewClientWithList[*tunedv1.Tuned, *tunedv1.TunedList]( "tuneds", c.RESTClient(), scheme.ParameterCodec, namespace, - func() *v1.Tuned { return &v1.Tuned{} }, - func() *v1.TunedList { return &v1.TunedList{} }), + func() *tunedv1.Tuned { return &tunedv1.Tuned{} }, + func() *tunedv1.TunedList { return &tunedv1.TunedList{} }, + ), } } diff --git a/pkg/generated/clientset/versioned/typed/tuned/v1/tuned_client.go b/pkg/generated/clientset/versioned/typed/tuned/v1/tuned_client.go index b1e8ec5f93..c632f8d60f 100644 --- a/pkg/generated/clientset/versioned/typed/tuned/v1/tuned_client.go +++ b/pkg/generated/clientset/versioned/typed/tuned/v1/tuned_client.go @@ -18,10 +18,10 @@ limitations under the License. package v1 import ( - "net/http" + http "net/http" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/scheme" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + scheme "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) @@ -89,10 +89,10 @@ func New(c rest.Interface) *TunedV1Client { } func setConfigDefaults(config *rest.Config) error { - gv := v1.SchemeGroupVersion + gv := tunedv1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index 405179e631..a17a63d677 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -18,7 +18,7 @@ limitations under the License. package externalversions import ( - "fmt" + fmt "fmt" v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" schema "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/pkg/generated/informers/externalversions/tuned/v1/profile.go b/pkg/generated/informers/externalversions/tuned/v1/profile.go index cbb0deac1d..207772398c 100644 --- a/pkg/generated/informers/externalversions/tuned/v1/profile.go +++ b/pkg/generated/informers/externalversions/tuned/v1/profile.go @@ -18,13 +18,13 @@ limitations under the License. package v1 import ( - "context" + context "context" time "time" - tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + apistunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" versioned "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned" internalinterfaces "github.com/openshift/cluster-node-tuning-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/listers/tuned/v1" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/listers/tuned/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -35,7 +35,7 @@ import ( // Profiles. type ProfileInformer interface { Informer() cache.SharedIndexInformer - Lister() v1.ProfileLister + Lister() tunedv1.ProfileLister } type profileInformer struct { @@ -70,7 +70,7 @@ func NewFilteredProfileInformer(client versioned.Interface, namespace string, re return client.TunedV1().Profiles(namespace).Watch(context.TODO(), options) }, }, - &tunedv1.Profile{}, + &apistunedv1.Profile{}, resyncPeriod, indexers, ) @@ -81,9 +81,9 @@ func (f *profileInformer) defaultInformer(client versioned.Interface, resyncPeri } func (f *profileInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&tunedv1.Profile{}, f.defaultInformer) + return f.factory.InformerFor(&apistunedv1.Profile{}, f.defaultInformer) } -func (f *profileInformer) Lister() v1.ProfileLister { - return v1.NewProfileLister(f.Informer().GetIndexer()) +func (f *profileInformer) Lister() tunedv1.ProfileLister { + return tunedv1.NewProfileLister(f.Informer().GetIndexer()) } diff --git a/pkg/generated/informers/externalversions/tuned/v1/tuned.go b/pkg/generated/informers/externalversions/tuned/v1/tuned.go index f6783ae6ec..666c002d95 100644 --- a/pkg/generated/informers/externalversions/tuned/v1/tuned.go +++ b/pkg/generated/informers/externalversions/tuned/v1/tuned.go @@ -18,13 +18,13 @@ limitations under the License. package v1 import ( - "context" + context "context" time "time" - tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + apistunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" versioned "github.com/openshift/cluster-node-tuning-operator/pkg/generated/clientset/versioned" internalinterfaces "github.com/openshift/cluster-node-tuning-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/listers/tuned/v1" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/generated/listers/tuned/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" @@ -35,7 +35,7 @@ import ( // Tuneds. type TunedInformer interface { Informer() cache.SharedIndexInformer - Lister() v1.TunedLister + Lister() tunedv1.TunedLister } type tunedInformer struct { @@ -70,7 +70,7 @@ func NewFilteredTunedInformer(client versioned.Interface, namespace string, resy return client.TunedV1().Tuneds(namespace).Watch(context.TODO(), options) }, }, - &tunedv1.Tuned{}, + &apistunedv1.Tuned{}, resyncPeriod, indexers, ) @@ -81,9 +81,9 @@ func (f *tunedInformer) defaultInformer(client versioned.Interface, resyncPeriod } func (f *tunedInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&tunedv1.Tuned{}, f.defaultInformer) + return f.factory.InformerFor(&apistunedv1.Tuned{}, f.defaultInformer) } -func (f *tunedInformer) Lister() v1.TunedLister { - return v1.NewTunedLister(f.Informer().GetIndexer()) +func (f *tunedInformer) Lister() tunedv1.TunedLister { + return tunedv1.NewTunedLister(f.Informer().GetIndexer()) } diff --git a/pkg/generated/listers/tuned/v1/profile.go b/pkg/generated/listers/tuned/v1/profile.go index ed32685cd5..9fdbb73cdc 100644 --- a/pkg/generated/listers/tuned/v1/profile.go +++ b/pkg/generated/listers/tuned/v1/profile.go @@ -18,10 +18,10 @@ limitations under the License. package v1 import ( - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/listers" - "k8s.io/client-go/tools/cache" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" ) // ProfileLister helps list Profiles. @@ -29,7 +29,7 @@ import ( type ProfileLister interface { // List lists all Profiles in the indexer. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1.Profile, err error) + List(selector labels.Selector) (ret []*tunedv1.Profile, err error) // Profiles returns an object that can list and get Profiles. Profiles(namespace string) ProfileNamespaceLister ProfileListerExpansion @@ -37,17 +37,17 @@ type ProfileLister interface { // profileLister implements the ProfileLister interface. type profileLister struct { - listers.ResourceIndexer[*v1.Profile] + listers.ResourceIndexer[*tunedv1.Profile] } // NewProfileLister returns a new ProfileLister. func NewProfileLister(indexer cache.Indexer) ProfileLister { - return &profileLister{listers.New[*v1.Profile](indexer, v1.Resource("profile"))} + return &profileLister{listers.New[*tunedv1.Profile](indexer, tunedv1.Resource("profile"))} } // Profiles returns an object that can list and get Profiles. func (s *profileLister) Profiles(namespace string) ProfileNamespaceLister { - return profileNamespaceLister{listers.NewNamespaced[*v1.Profile](s.ResourceIndexer, namespace)} + return profileNamespaceLister{listers.NewNamespaced[*tunedv1.Profile](s.ResourceIndexer, namespace)} } // ProfileNamespaceLister helps list and get Profiles. @@ -55,15 +55,15 @@ func (s *profileLister) Profiles(namespace string) ProfileNamespaceLister { type ProfileNamespaceLister interface { // List lists all Profiles in the indexer for a given namespace. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1.Profile, err error) + List(selector labels.Selector) (ret []*tunedv1.Profile, err error) // Get retrieves the Profile from the indexer for a given namespace and name. // Objects returned here must be treated as read-only. - Get(name string) (*v1.Profile, error) + Get(name string) (*tunedv1.Profile, error) ProfileNamespaceListerExpansion } // profileNamespaceLister implements the ProfileNamespaceLister // interface. type profileNamespaceLister struct { - listers.ResourceIndexer[*v1.Profile] + listers.ResourceIndexer[*tunedv1.Profile] } diff --git a/pkg/generated/listers/tuned/v1/tuned.go b/pkg/generated/listers/tuned/v1/tuned.go index b2f34e22c4..dc93cb4824 100644 --- a/pkg/generated/listers/tuned/v1/tuned.go +++ b/pkg/generated/listers/tuned/v1/tuned.go @@ -18,10 +18,10 @@ limitations under the License. package v1 import ( - v1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/listers" - "k8s.io/client-go/tools/cache" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" ) // TunedLister helps list Tuneds. @@ -29,7 +29,7 @@ import ( type TunedLister interface { // List lists all Tuneds in the indexer. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1.Tuned, err error) + List(selector labels.Selector) (ret []*tunedv1.Tuned, err error) // Tuneds returns an object that can list and get Tuneds. Tuneds(namespace string) TunedNamespaceLister TunedListerExpansion @@ -37,17 +37,17 @@ type TunedLister interface { // tunedLister implements the TunedLister interface. type tunedLister struct { - listers.ResourceIndexer[*v1.Tuned] + listers.ResourceIndexer[*tunedv1.Tuned] } // NewTunedLister returns a new TunedLister. func NewTunedLister(indexer cache.Indexer) TunedLister { - return &tunedLister{listers.New[*v1.Tuned](indexer, v1.Resource("tuned"))} + return &tunedLister{listers.New[*tunedv1.Tuned](indexer, tunedv1.Resource("tuned"))} } // Tuneds returns an object that can list and get Tuneds. func (s *tunedLister) Tuneds(namespace string) TunedNamespaceLister { - return tunedNamespaceLister{listers.NewNamespaced[*v1.Tuned](s.ResourceIndexer, namespace)} + return tunedNamespaceLister{listers.NewNamespaced[*tunedv1.Tuned](s.ResourceIndexer, namespace)} } // TunedNamespaceLister helps list and get Tuneds. @@ -55,15 +55,15 @@ func (s *tunedLister) Tuneds(namespace string) TunedNamespaceLister { type TunedNamespaceLister interface { // List lists all Tuneds in the indexer for a given namespace. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1.Tuned, err error) + List(selector labels.Selector) (ret []*tunedv1.Tuned, err error) // Get retrieves the Tuned from the indexer for a given namespace and name. // Objects returned here must be treated as read-only. - Get(name string) (*v1.Tuned, error) + Get(name string) (*tunedv1.Tuned, error) TunedNamespaceListerExpansion } // tunedNamespaceLister implements the TunedNamespaceLister // interface. type tunedNamespaceLister struct { - listers.ResourceIndexer[*v1.Tuned] + listers.ResourceIndexer[*tunedv1.Tuned] } diff --git a/pkg/tuned/controller.go b/pkg/tuned/controller.go index 374e688245..dd87b22e1d 100644 --- a/pkg/tuned/controller.go +++ b/pkg/tuned/controller.go @@ -154,6 +154,8 @@ type Change struct { provider string // Should we turn the reapply_sysctl TuneD option on in tuned-main.conf file? reapplySysctl bool + // What should be the value of the startup_udev_settle_wait TuneD option in tuned-main.conf file? + startupUdevSettleWait uint64 // The current recommended profile as calculated by the operator. recommendedProfile string @@ -187,6 +189,9 @@ func (ch Change) String() string { if ch.reapplySysctl { items = append(items, "reapplySysctl:true") } + if ch.startupUdevSettleWait != 0 { + items = append(items, fmt.Sprintf("startupUdevSettleWait:%d", ch.startupUdevSettleWait)) + } if ch.recommendedProfile != "" { items = append(items, fmt.Sprintf("recommendedProfile:%q", ch.recommendedProfile)) } @@ -358,10 +363,16 @@ func (c *Controller) sync(key wqKeyKube) error { } else { klog.Infof("set log level %d", profile.Spec.Config.Verbosity) } + // The default value of 'reapply_sysctl' is True in both NTO and TuneD. change.reapplySysctl = true if profile.Spec.Config.TuneDConfig.ReapplySysctl != nil { change.reapplySysctl = *profile.Spec.Config.TuneDConfig.ReapplySysctl } + // The default value of 'startup_udev_settle_wait' is 20 in NTO. + change.startupUdevSettleWait = 20 + if profile.Spec.Config.TuneDConfig.StartupUdevSettleWait != nil { + change.startupUdevSettleWait = *profile.Spec.Config.TuneDConfig.StartupUdevSettleWait + } change.deferredMode = util.GetDeferredUpdateAnnotation(profile.Annotations) // Notify the event processor that the Profile k8s object containing information about which TuneD profile to apply changed. c.wqTuneD.Add(wqKeyTuned{kind: wqKindDaemon, change: change}) @@ -1064,7 +1075,14 @@ func (c *Controller) changeSyncerTuneD(change Change) (synced bool, err error) { } // Does the current TuneD process have the reapply_sysctl option turned on? - if reapplySysctl := c.tunedMainCfg.Section("").Key("reapply_sysctl").MustBool(); reapplySysctl != change.reapplySysctl { + var reapplySysctl bool + if len(c.tunedMainCfg.Section("").Key("reapply_sysctl").Value()) == 0 { + // The default value of 'reapply_sysctl' is True when undefined. + reapplySysctl = true + } else { + reapplySysctl = c.tunedMainCfg.Section("").Key("reapply_sysctl").MustBool() + } + if reapplySysctl != change.reapplySysctl { klog.V(4).Infof("reapplySysctl rewriting configuration file") if err = iniCfgSetKey(c.tunedMainCfg, "reapply_sysctl", !reapplySysctl); err != nil { return false, err @@ -1076,6 +1094,21 @@ func (c *Controller) changeSyncerTuneD(change Change) (synced bool, err error) { klog.V(4).Infof("reapplySysctl triggering tuned restart") restart = true // A complete restart of the TuneD daemon is needed due to configuration change in tuned-main.conf file. } + + // Does the current TuneD process have the startup_udev_settle_wait option turned on? + // The default value of 'startup_udev_settle_wait' is 0 when the option is not defined, which matches the logic (value 0) below. + if startupUdevSettleWait := c.tunedMainCfg.Section("").Key("startup_udev_settle_wait").MustUint64(); startupUdevSettleWait != change.startupUdevSettleWait { + klog.V(4).Infof("startupUdevSettleWait rewriting configuration file") + if err = iniCfgSetKey(c.tunedMainCfg, "startup_udev_settle_wait", change.startupUdevSettleWait); err != nil { + return false, err + } + err = iniFileSave(tunedMainConfPath, c.tunedMainCfg) + if err != nil { + return false, fmt.Errorf("failed to write global TuneD configuration file: %w", err) + } + klog.V(4).Infof("startupUdevSettleWait triggering tuned restart") + restart = true // A complete restart of the TuneD daemon is needed due to configuration change in tuned-main.conf file. + } } // failures pertaining to deferred updates are not critical diff --git a/pkg/tuned/controller_test.go b/pkg/tuned/controller_test.go index 679653ae5c..2c5eb17e3c 100644 --- a/pkg/tuned/controller_test.go +++ b/pkg/tuned/controller_test.go @@ -273,7 +273,7 @@ func TestChangeString(t *testing.T) { { name: "full", change: fullChange(), - expected: fmt.Sprintf("%#v", fullChange()), + expected: fmt.Sprintf("%v", fullChange()), }, } for _, tt := range testCases { @@ -288,16 +288,17 @@ func TestChangeString(t *testing.T) { func fullChange() Change { return Change{ - profile: true, - profileStatus: true, - tunedReload: true, - nodeRestart: true, - debug: true, - provider: "test-provider", - reapplySysctl: true, - recommendedProfile: "test-profile", - deferredMode: util.DeferAlways, - message: "test-message", + profile: true, + profileStatus: true, + tunedReload: true, + nodeRestart: true, + debug: true, + provider: "test-provider", + reapplySysctl: true, + startupUdevSettleWait: 20, + recommendedProfile: "test-profile", + deferredMode: util.DeferAlways, + message: "test-message", } } diff --git a/test/e2e/basic/udev_settle_wait.go b/test/e2e/basic/udev_settle_wait.go new file mode 100644 index 0000000000..3a474d9866 --- /dev/null +++ b/test/e2e/basic/udev_settle_wait.go @@ -0,0 +1,123 @@ +package e2e + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + + coreapi "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/wait" + + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + ntoconfig "github.com/openshift/cluster-node-tuning-operator/pkg/config" + util "github.com/openshift/cluster-node-tuning-operator/test/e2e/util" +) + +var _ = ginkgo.Describe("[basic][startup_udev_settle_wait] Node Tuning Operator /etc/tuned/tuned-main.conf startup_udev_settle_wait setting", func() { + const ( + tunedMainConfVar = "startup_udev_settle_wait" + tunedMainConfPath = "/etc/tuned/tuned-main.conf" + profileUdevSettleWait = "../testing_manifests/udev_settle_wait.yaml" + nodeLabelUdevSettleWait = "tuned.openshift.io/udev-settle-wait" + ) + + ginkgo.Context("startup_udev_settle_wait setting", func() { + var ( + node *coreapi.Node + pod *coreapi.Pod + ) + + // Cleanup code to roll back cluster changes done by this test even if it fails in the middle of ginkgo.It() + ginkgo.AfterEach(func() { + // Ignore failures to cleanup resources which are already deleted or not yet created. + ginkgo.By("cluster changes rollback") + + if node != nil { + _, _, _ = util.ExecAndLogCommand("oc", "label", "node", "--overwrite", node.Name, nodeLabelUdevSettleWait+"-") + } + _, _, _ = util.ExecAndLogCommand("oc", "delete", "-n", ntoconfig.WatchNamespace(), "-f", profileUdevSettleWait) + }) + + ginkgo.It(fmt.Sprintf("%s set", tunedMainConfVar), func() { + const ( + pollInterval = 5 * time.Second + waitDuration = 5 * time.Minute + ) + var explain string + + ginkgo.By("getting a list of worker nodes") + nodes, err := util.GetNodesByRole(cs, "worker") + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(len(nodes)).NotTo(gomega.BeZero(), "number of worker nodes is 0") + + node = &nodes[0] + ginkgo.By(fmt.Sprintf("getting a TuneD Pod running on node %s", node.Name)) + pod, err = util.GetTunedForNode(cs, node) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + // Expect the default worker node profile applied prior to getting any current values. + ginkgo.By(fmt.Sprintf("waiting for TuneD profile %s on node %s", util.GetDefaultWorkerProfile(node), node.Name)) + err = util.WaitForProfileConditionStatus(cs, pollInterval, waitDuration, node.Name, util.GetDefaultWorkerProfile(node), tunedv1.TunedProfileApplied, coreapi.ConditionTrue) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + getOptionInTunedMainConf := func(opt string) (string, error) { + out, err := util.ExecCmdInPod(pod, "sed", "-En", `s/^(\s*`+opt+`\s*=\s*)(\d*)/\2/p`, tunedMainConfPath) + out = strings.TrimSpace(out) + return out, err + } + + ginkgo.By(fmt.Sprintf("getting the default value of startup_udev_settle_wait in %s", tunedMainConfPath)) + out, err := getOptionInTunedMainConf(tunedMainConfVar) + valOrig := out + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + ginkgo.By(fmt.Sprintf("labelling node %s with label %s", node.Name, nodeLabelUdevSettleWait)) + _, _, err = util.ExecAndLogCommand("oc", "label", "node", "--overwrite", node.Name, nodeLabelUdevSettleWait+"=") + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + ginkgo.By(fmt.Sprintf("creating the custom profile %s", profileUdevSettleWait)) + _, _, err = util.ExecAndLogCommand("oc", "create", "-n", ntoconfig.WatchNamespace(), "-f", profileUdevSettleWait) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + ginkgo.By(fmt.Sprintf("waiting for %s=10 in %s", tunedMainConfVar, tunedMainConfPath)) + err = wait.PollUntilContextTimeout(context.TODO(), pollInterval, waitDuration, true, func(ctx context.Context) (bool, error) { + out, err := getOptionInTunedMainConf(tunedMainConfVar) + if err != nil { + explain = err.Error() + return false, nil + } + if out != "10" { + return false, nil + } + return true, nil + }) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), explain) + + ginkgo.By(fmt.Sprintf("removing label %s from node %s", nodeLabelUdevSettleWait, node.Name)) + _, _, err = util.ExecAndLogCommand("oc", "label", "node", "--overwrite", node.Name, nodeLabelUdevSettleWait+"-") + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + ginkgo.By(fmt.Sprintf("deleting the custom profile %s", profileUdevSettleWait)) + _, _, err = util.ExecAndLogCommand("oc", "delete", "-n", ntoconfig.WatchNamespace(), "-f", profileUdevSettleWait) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + ginkgo.By(fmt.Sprintf("waiting for %s=%s in %s", tunedMainConfVar, valOrig, tunedMainConfPath)) + err = wait.PollUntilContextTimeout(context.TODO(), pollInterval, waitDuration, true, func(ctx context.Context) (bool, error) { + out, err := getOptionInTunedMainConf(tunedMainConfVar) + if err != nil { + explain = err.Error() + return false, nil + } + if out != valOrig { + return false, nil + } + return true, nil + }) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), explain) + }) + }) +}) diff --git a/test/e2e/performanceprofile/functests/3_performance_status/status.go b/test/e2e/performanceprofile/functests/3_performance_status/status.go index 5806a6a2ef..da8ebc1b79 100644 --- a/test/e2e/performanceprofile/functests/3_performance_status/status.go +++ b/test/e2e/performanceprofile/functests/3_performance_status/status.go @@ -7,17 +7,17 @@ import ( "github.com/onsi/gomega/gcustom" types2 "github.com/onsi/gomega/types" - tunedutils "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/tuned" +// tunedutils "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/tuned" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - nodev1 "k8s.io/api/node/v1" +// nodev1 "k8s.io/api/node/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" utilrand "k8s.io/apimachinery/pkg/util/rand" - "sigs.k8s.io/controller-runtime/pkg/client" +// "sigs.k8s.io/controller-runtime/pkg/client" ign2types "github.com/coreos/ignition/config/v2_2/types" machineconfigv1 "github.com/openshift/api/machineconfiguration/v1" @@ -28,11 +28,12 @@ import ( "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/discovery" hypershiftutils "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/hypershift" "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/label" - "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/mcps" +// "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/mcps" "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/nodepools" "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/nodes" "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/profiles" v1 "github.com/openshift/custom-resource-status/conditions/v1" + "github.com/openshift/cluster-node-tuning-operator/test/e2e/util" ) var _ = Describe("Status testing of performance profile", Ordered, func() { @@ -53,68 +54,68 @@ var _ = Describe("Status testing of performance profile", Ordered, func() { }) Context("[rfe_id:28881][performance] Performance Addons detailed status", Label(string(label.Tier1)), func() { - It("[test_id:30894] Tuned status name tied to Performance Profile", func() { - profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) - Expect(err).ToNot(HaveOccurred()) - tunedList := &tunedv1.TunedList{} - tunedName, err := tunedutils.GetName(context.TODO(), testclient.ControlPlaneClient, profile.Name) - Expect(err).ToNot(HaveOccurred()) - tunedNamespacedName := types.NamespacedName{ - Name: tunedName, - Namespace: components.NamespaceNodeTuningOperator, - } - // on hypershift platform, we're getting the tuned object that was mirrored by NTO to the hosted cluster, - // hence we're using the DataPlaneClient here. - Eventually(func(g Gomega) { - g.Expect(testclient.DataPlaneClient.List(context.TODO(), tunedList, &client.ListOptions{ - Namespace: tunedNamespacedName.Namespace, - })).To(Succeed()) - Expect(tunedList.Items).To(MatchTunedName(tunedName)) - }).WithTimeout(time.Minute).WithPolling(time.Second * 10).Should(Succeed()) - Expect(*profile.Status.Tuned).ToNot(BeNil()) - Expect(*profile.Status.Tuned).To(Equal(tunedNamespacedName.String())) - }) - - It("[test_id:33791] Should include the generated runtime class name", func() { - profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) - Expect(err).ToNot(HaveOccurred()) - - key := types.NamespacedName{ - Name: components.GetComponentName(profile.Name, components.ComponentNamePrefix), - Namespace: metav1.NamespaceAll, - } - runtimeClass := &nodev1.RuntimeClass{} - err = testclient.GetWithRetry(context.TODO(), testclient.DataPlaneClient, key, runtimeClass) - Expect(err).ToNot(HaveOccurred(), "cannot find the RuntimeClass object "+key.String()) - - Expect(profile.Status.RuntimeClass).NotTo(BeNil()) - Expect(*profile.Status.RuntimeClass).To(Equal(runtimeClass.Name)) - }) - - It("[test_id:29673] Machine config pools status tied to Performance Profile", Label(string(label.OpenShift)), func() { - // Creating bad MC that leads to degraded state - By("Creating bad MachineConfig") - badMC := createBadMachineConfig("bad-mc") - err = testclient.ControlPlaneClient.Create(context.TODO(), badMC) - Expect(err).ToNot(HaveOccurred()) - - By("Wait for MCP condition to be Degraded") - profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) - Expect(err).ToNot(HaveOccurred()) - performanceMCP, err := mcps.GetByProfile(profile) - Expect(err).ToNot(HaveOccurred()) - mcps.WaitForCondition(performanceMCP, machineconfigv1.MachineConfigPoolDegraded, corev1.ConditionTrue) - mcpConditionReason := mcps.GetConditionReason(performanceMCP, machineconfigv1.MachineConfigPoolDegraded) - profileConditionMessage := profiles.GetConditionMessage(testutils.NodeSelectorLabels, v1.ConditionDegraded) - // Verify the status reason of performance profile - Expect(profileConditionMessage).To(ContainSubstring(mcpConditionReason)) - - By("Deleting bad MachineConfig and waiting when Degraded state is removed") - err = testclient.ControlPlaneClient.Delete(context.TODO(), badMC) - Expect(err).ToNot(HaveOccurred()) - - mcps.WaitForCondition(performanceMCP, machineconfigv1.MachineConfigPoolUpdated, corev1.ConditionTrue) - }) +// It("[test_id:30894] Tuned status name tied to Performance Profile", func() { +// profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) +// Expect(err).ToNot(HaveOccurred()) +// tunedList := &tunedv1.TunedList{} +// tunedName, err := tunedutils.GetName(context.TODO(), testclient.ControlPlaneClient, profile.Name) +// Expect(err).ToNot(HaveOccurred()) +// tunedNamespacedName := types.NamespacedName{ +// Name: tunedName, +// Namespace: components.NamespaceNodeTuningOperator, +// } +// // on hypershift platform, we're getting the tuned object that was mirrored by NTO to the hosted cluster, +// // hence we're using the DataPlaneClient here. +// Eventually(func(g Gomega) { +// g.Expect(testclient.DataPlaneClient.List(context.TODO(), tunedList, &client.ListOptions{ +// Namespace: tunedNamespacedName.Namespace, +// })).To(Succeed()) +// Expect(tunedList.Items).To(MatchTunedName(tunedName)) +// }).WithTimeout(time.Minute).WithPolling(time.Second * 10).Should(Succeed()) +// Expect(*profile.Status.Tuned).ToNot(BeNil()) +// Expect(*profile.Status.Tuned).To(Equal(tunedNamespacedName.String())) +// }) +// +// It("[test_id:33791] Should include the generated runtime class name", func() { +// profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) +// Expect(err).ToNot(HaveOccurred()) +// +// key := types.NamespacedName{ +// Name: components.GetComponentName(profile.Name, components.ComponentNamePrefix), +// Namespace: metav1.NamespaceAll, +// } +// runtimeClass := &nodev1.RuntimeClass{} +// err = testclient.GetWithRetry(context.TODO(), testclient.DataPlaneClient, key, runtimeClass) +// Expect(err).ToNot(HaveOccurred(), "cannot find the RuntimeClass object "+key.String()) +// +// Expect(profile.Status.RuntimeClass).NotTo(BeNil()) +// Expect(*profile.Status.RuntimeClass).To(Equal(runtimeClass.Name)) +// }) +// +// It("[test_id:29673] Machine config pools status tied to Performance Profile", Label(string(label.OpenShift)), func() { +// // Creating bad MC that leads to degraded state +// By("Creating bad MachineConfig") +// badMC := createBadMachineConfig("bad-mc") +// err = testclient.ControlPlaneClient.Create(context.TODO(), badMC) +// Expect(err).ToNot(HaveOccurred()) +// +// By("Wait for MCP condition to be Degraded") +// profile, err := profiles.GetByNodeLabels(testutils.NodeSelectorLabels) +// Expect(err).ToNot(HaveOccurred()) +// performanceMCP, err := mcps.GetByProfile(profile) +// Expect(err).ToNot(HaveOccurred()) +// mcps.WaitForCondition(performanceMCP, machineconfigv1.MachineConfigPoolDegraded, corev1.ConditionTrue) +// mcpConditionReason := mcps.GetConditionReason(performanceMCP, machineconfigv1.MachineConfigPoolDegraded) +// profileConditionMessage := profiles.GetConditionMessage(testutils.NodeSelectorLabels, v1.ConditionDegraded) +// // Verify the status reason of performance profile +// Expect(profileConditionMessage).To(ContainSubstring(mcpConditionReason)) +// +// By("Deleting bad MachineConfig and waiting when Degraded state is removed") +// err = testclient.ControlPlaneClient.Delete(context.TODO(), badMC) +// Expect(err).ToNot(HaveOccurred()) +// +// mcps.WaitForCondition(performanceMCP, machineconfigv1.MachineConfigPoolUpdated, corev1.ConditionTrue) +// }) It("[test_id:40402] Tuned profile status tied to Performance Profile", func() { // During this test we're creating additional synthetic tuned CR by invoking the createrBadTuned function. @@ -127,16 +128,38 @@ var _ = Describe("Status testing of performance profile", Ordered, func() { // on openshift this is the namespace where NTO/PAO creates tuned objects ns := components.NamespaceNodeTuningOperator + By("1) ------------") + _, _, err = util.ExecAndLogCommand("oc", "get", "tuned", "-n", ns) + _, _, err = util.ExecAndLogCommand("oc", "get", "profile", "-n", ns) +// _, _, err = util.ExecAndLogCommand("oc", "get", "performanceprofile/performance", "-n", ns, "-o", "yaml") + // Creating a bad Tuned object that leads to degraded state cleanupFunc := createBadTuned(tunedName, ns) defer func() { + By("2b) ------------") + _, _, err = util.ExecAndLogCommand("oc", "get", "tuned", "-n", ns) + _, _, err = util.ExecAndLogCommand("oc", "get", "profile", "-n", ns) + By("Deleting bad Tuned and waiting when Degraded state is removed") cleanupFunc() + + By("3) Sleeping 30") + time.Sleep(30 * time.Second) + + _, _, err = util.ExecAndLogCommand("oc", "get", "tuned", "-n", ns) + _, _, err = util.ExecAndLogCommand("oc", "get", "profile", "-n", ns) +// _, _, err = util.ExecAndLogCommand("oc", "get", "performanceprofile/performance", "-n", ns, "-o", "yaml") + profiles.WaitForCondition(testutils.NodeSelectorLabels, v1.ConditionAvailable, corev1.ConditionTrue) }() By("Waiting for performance profile condition to be Degraded") profiles.WaitForCondition(testutils.NodeSelectorLabels, v1.ConditionDegraded, corev1.ConditionTrue) + + By("2) ------------") + _, _, err = util.ExecAndLogCommand("oc", "get", "tuned", "-n", ns) + _, _, err = util.ExecAndLogCommand("oc", "get", "profile", "-n", ns) +// _, _, err = util.ExecAndLogCommand("oc", "get", "performanceprofile/performance", "-n", ns, "-o", "yaml") }) }) }) diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-master_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-master_tuned.yaml index 037bf82d28..5db11c867e 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-master_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-master_tuned.yaml @@ -143,6 +143,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-openshift-bootstrap-master status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-worker_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-worker_tuned.yaml index cc1d3771cb..374353d39e 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-worker_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/extra-mcp/openshift-bootstrap-worker_tuned.yaml @@ -143,6 +143,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-openshift-bootstrap-worker status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-master_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-master_tuned.yaml index 037bf82d28..5db11c867e 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-master_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-master_tuned.yaml @@ -143,6 +143,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-openshift-bootstrap-master status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-worker_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-worker_tuned.yaml index cc1d3771cb..374353d39e 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-worker_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/bootstrap/no-mcp/openshift-bootstrap-worker_tuned.yaml @@ -143,6 +143,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-openshift-bootstrap-worker status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/default/arm/manual_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/default/arm/manual_tuned.yaml index c9868ee6a0..655d3c8f43 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/default/arm/manual_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/default/arm/manual_tuned.yaml @@ -142,6 +142,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-manual status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/default/cpuFrequency/manual_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/default/cpuFrequency/manual_tuned.yaml index 54b71a69b3..430803a52a 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/default/cpuFrequency/manual_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/default/cpuFrequency/manual_tuned.yaml @@ -143,6 +143,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-manual status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/default/manual_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/default/manual_tuned.yaml index 249f3d6230..1cde6ae843 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/default/manual_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/default/manual_tuned.yaml @@ -144,6 +144,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-manual status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/default/pp-norps/manual_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/default/pp-norps/manual_tuned.yaml index 249f3d6230..1cde6ae843 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/default/pp-norps/manual_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/default/pp-norps/manual_tuned.yaml @@ -144,6 +144,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-manual status: {} diff --git a/test/e2e/performanceprofile/testdata/render-expected-output/no-ref/manual_tuned.yaml b/test/e2e/performanceprofile/testdata/render-expected-output/no-ref/manual_tuned.yaml index 8b5813bc3d..bcfbdd66b1 100644 --- a/test/e2e/performanceprofile/testdata/render-expected-output/no-ref/manual_tuned.yaml +++ b/test/e2e/performanceprofile/testdata/render-expected-output/no-ref/manual_tuned.yaml @@ -142,6 +142,7 @@ spec: operand: tunedConfig: reapply_sysctl: null + startup_udev_settle_wait: null priority: 20 profile: openshift-node-performance-manual status: {} diff --git a/test/e2e/testing_manifests/udev_settle_wait.yaml b/test/e2e/testing_manifests/udev_settle_wait.yaml new file mode 100644 index 0000000000..74e54d432f --- /dev/null +++ b/test/e2e/testing_manifests/udev_settle_wait.yaml @@ -0,0 +1,20 @@ +apiVersion: tuned.openshift.io/v1 +kind: Tuned +metadata: + name: openshift-profile + namespace: openshift-cluster-node-tuning-operator +spec: + profile: + - data: | + [main] + summary=Custom OpenShift profile + include=openshift-node + name: openshift-profile + recommend: + - match: + - label: tuned.openshift.io/udev-settle-wait + priority: 20 + profile: openshift-profile + operand: + tunedConfig: + startup_udev_settle_wait: 10