diff --git a/test/e2e/performanceprofile/functests/utils/client/clients.go b/test/e2e/performanceprofile/functests/utils/client/clients.go index 02f6c26943..b3969ce760 100644 --- a/test/e2e/performanceprofile/functests/utils/client/clients.go +++ b/test/e2e/performanceprofile/functests/utils/client/clients.go @@ -14,19 +14,27 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" configv1 "github.com/openshift/api/config/v1" - tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" - mcov1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" performancev1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/performanceprofile/v1" performancev1alpha1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/performanceprofile/v1alpha1" performancev2 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/performanceprofile/v2" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + ntoconfig "github.com/openshift/cluster-node-tuning-operator/pkg/config" + "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/hypershift" testlog "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/log" + mcov1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1" + apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" ) var ( - // Client defines the API client to run CRUD operations, that will be used for testing + // Client kept for backport compatibility until all tests will be converted Client client.Client + // ControlPlaneClient defines the API client to run CRUD operations on the control plane cluster, + //that will be used for testing + ControlPlaneClient client.Client + // DataPlaneClient defines the API client to run CRUD operations on the data plane cluster, + //that will be used for testing + DataPlaneClient client.Client // K8sClient defines k8s client to run subresource operations, for example you should use it to get pod logs K8sClient *kubernetes.Clientset // ClientsEnabled tells if the client from the package can be used @@ -67,27 +75,55 @@ func init() { Client, err = New() if err != nil { testlog.Info("Failed to initialize client, check the KUBECONFIG env variable", err.Error()) - ClientsEnabled = false + return + } + + ControlPlaneClient, err = NewControlPlane() + if err != nil { + testlog.Info("Failed to initialize ControlPlaneClient client, check the KUBECONFIG env variable", err.Error()) + return + } + DataPlaneClient, err = NewDataPlane() + if err != nil { + testlog.Info("Failed to initialize DataPlaneClient client, check the KUBECONFIG env variable", err.Error()) return } K8sClient, err = NewK8s() if err != nil { testlog.Info("Failed to initialize k8s client, check the KUBECONFIG env variable", err.Error()) - ClientsEnabled = false return } ClientsEnabled = true } -// New returns a controller-runtime client. func New() (client.Client, error) { cfg, err := config.GetConfig() if err != nil { return nil, err } + return client.New(cfg, client.Options{}) +} - c, err := client.New(cfg, client.Options{}) - return c, err +// NewControlPlane returns a new controller-runtime client for ControlPlaneClient cluster. +func NewControlPlane() (client.Client, error) { + if ntoconfig.InHyperShift() { + testlog.Info("creating ControlPlaneClient client for hypershift cluster") + return hypershift.BuildControlPlaneClient() + } + return New() +} + +// NewDataPlane returns a new controller-runtime client for DataPlaneClient cluster. +func NewDataPlane() (client.Client, error) { + var c client.Client + var err error + if ntoconfig.InHyperShift() { + testlog.Info("creating DataPlaneClient client for hypershift cluster") + c, err = hypershift.BuildDataPlaneClient() + } else { + c, err = New() + } + return &dataPlaneImpl{c}, err } // NewK8s returns a kubernetes clientset diff --git a/test/e2e/performanceprofile/functests/utils/client/dataplane.go b/test/e2e/performanceprofile/functests/utils/client/dataplane.go new file mode 100644 index 0000000000..c1c4758963 --- /dev/null +++ b/test/e2e/performanceprofile/functests/utils/client/dataplane.go @@ -0,0 +1,70 @@ +package client + +import ( + "context" + "fmt" + + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/hypershift" +) + +type dataPlaneImpl struct { + client.Client +} + +func (dpi *dataPlaneImpl) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not be presented on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.Get(ctx, key, obj, opts...) +} + +func (dpi *dataPlaneImpl) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(list) { + return fmt.Errorf("the provided list of %s objects might not be presented on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", list.GetObjectKind()) + } + return dpi.Client.List(ctx, list, opts...) +} + +func (dpi *dataPlaneImpl) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not get created on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.Create(ctx, obj, opts...) +} + +func (dpi *dataPlaneImpl) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not get deleted on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.Delete(ctx, obj, opts...) +} + +func (dpi *dataPlaneImpl) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not get updated on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.Update(ctx, obj, opts...) +} + +func (dpi *dataPlaneImpl) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not get patched on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.Patch(ctx, obj, patch, opts...) +} + +func (dpi *dataPlaneImpl) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { + if hypershift.ObjIsEncapsulatedInConfigMap(obj) { + return fmt.Errorf("the provided object %s/%s might not get deleted on hypershift cluster while using this client."+ + "please use ControlPlaneClient client instead", obj.GetObjectKind(), obj.GetName()) + } + return dpi.Client.DeleteAllOf(ctx, obj, opts...) +} diff --git a/test/e2e/performanceprofile/functests/utils/hypershift/hypershift.go b/test/e2e/performanceprofile/functests/utils/hypershift/hypershift.go new file mode 100644 index 0000000000..bd88545893 --- /dev/null +++ b/test/e2e/performanceprofile/functests/utils/hypershift/hypershift.go @@ -0,0 +1,114 @@ +package hypershift + +import ( + "context" + "fmt" + "os" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + + performancev2 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/performanceprofile/v2" + tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" + machineconfigv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1" +) + +const ( + ManagementClusterKubeConfigEnv = "HYPERSHIFT_MANAGEMENT_CLUSTER_KUBECONFIG" + ManagementClusterNamespaceEnv = "HYPERSHIFT_MANAGEMENT_CLUSTER_NAMESPACE" + HostedClusterKubeConfigEnv = "HYPERSHIFT_HOSTED_CLUSTER_KUBECONFIG" +) + +// a set of keys which used to classify the encapsulated objects in the ConfigMap +const ( + TuningKey = "tuning" + ConfigKey = "config" +) + +type ControlPlaneClientImpl struct { + // A client with access to the management cluster + client.Client + + // managementClusterNamespaceName is the namespace name on the management cluster + // on which the control-plane objects reside + managementClusterNamespaceName string +} + +func (ci *ControlPlaneClientImpl) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if ObjIsEncapsulatedInConfigMap(obj) { + return ci.getFromConfigMap(ctx, key, obj, opts...) + } + return ci.Client.Get(ctx, key, obj, opts...) +} + +func buildClient(kubeConfigPath string) (client.Client, error) { + restConfig, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) + if err != nil { + return nil, err + } + c, err := client.New(restConfig, client.Options{}) + if err != nil { + return nil, err + } + return c, nil +} + +func ObjIsEncapsulatedInConfigMap(obj runtime.Object) bool { + switch obj.(type) { + case *performancev2.PerformanceProfile, *performancev2.PerformanceProfileList, + *machineconfigv1.KubeletConfig, *machineconfigv1.KubeletConfigList, + *machineconfigv1.MachineConfig, *machineconfigv1.MachineConfigList, + *tunedv1.Profile, *tunedv1.ProfileList: + return true + default: + return false + } +} + +func BuildControlPlaneClient() (client.Client, error) { + kcPath, ok := os.LookupEnv(ManagementClusterKubeConfigEnv) + if !ok { + return nil, fmt.Errorf("failed to build management-cluster client for hypershift, environment variable %q is not defined", ManagementClusterKubeConfigEnv) + } + c, err := buildClient(kcPath) + if err != nil { + return nil, err + } + ns, ok := os.LookupEnv(ManagementClusterNamespaceEnv) + if !ok { + return nil, fmt.Errorf("failed to build management-cluster client for hypershift, environment variable %q is not defined", ManagementClusterNamespaceEnv) + } + return &ControlPlaneClientImpl{ + Client: c, + managementClusterNamespaceName: ns, + }, nil +} + +func BuildDataPlaneClient() (client.Client, error) { + kcPath, ok := os.LookupEnv(HostedClusterKubeConfigEnv) + if !ok { + return nil, fmt.Errorf("failed to build hosted-cluster client for hypershift, environment variable %q is not defined", HostedClusterKubeConfigEnv) + } + return buildClient(kcPath) +} + +func (ci *ControlPlaneClientImpl) getFromConfigMap(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + cm := &corev1.ConfigMap{} + key.Namespace = ci.managementClusterNamespaceName + err := ci.Client.Get(ctx, key, cm, opts...) + if err != nil { + return err + } + var objAsYAML string + // can't have both + if s, ok := cm.Data[TuningKey]; ok { + objAsYAML = s + } + if s, ok := cm.Data[ConfigKey]; ok { + objAsYAML = s + } + return yaml.Unmarshal([]byte(objAsYAML), obj) +}