github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/test/util/util.go (about)

     1  package util
     2  
     3  import (
     4  	goctx "context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  
     9  	// "strings"
    10  	// "testing"
    11  	"time"
    12  
    13  	dptypes "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/types"
    14  	// "github.com/operator-framework/operator-sdk/pkg/test/e2eutil"
    15  	appsv1 "k8s.io/api/apps/v1"
    16  	// corev1 "k8s.io/api/core/v1"
    17  	"k8s.io/apimachinery/pkg/api/errors"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/types"
    20  	"k8s.io/apimachinery/pkg/util/wait"
    21  	client "sigs.k8s.io/controller-runtime/pkg/client"
    22  
    23  	// "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/apis"
    24  	sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
    25  )
    26  
    27  var (
    28  	RetryInterval        = time.Second * 1
    29  	APITimeout           = time.Second * 20
    30  	Timeout              = time.Second * 60
    31  	CleanupRetryInterval = time.Second * 1
    32  	CleanupTimeout       = time.Second * 5
    33  )
    34  
    35  func WaitForSriovNetworkNodeStateReady(nodeState *sriovnetworkv1.SriovNetworkNodeState, client client.Client, namespace, name string, retryInterval, timeout time.Duration) error {
    36  	time.Sleep(30 * time.Second)
    37  	err := wait.PollImmediate(retryInterval, timeout, func() (done bool, err error) {
    38  		ctx, cancel := goctx.WithTimeout(goctx.Background(), APITimeout)
    39  		defer cancel()
    40  		err = client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, nodeState)
    41  		if err != nil {
    42  			if errors.IsNotFound(err) {
    43  				return false, nil
    44  			}
    45  			return false, err
    46  		}
    47  		if nodeState.Status.SyncStatus != "Succeeded" {
    48  			return false, nil
    49  		}
    50  		return true, nil
    51  	})
    52  	if err != nil {
    53  		fmt.Printf("failed to wait for ds %s/%s to be ready: %v", namespace, name, err)
    54  		return err
    55  	}
    56  
    57  	return nil
    58  }
    59  
    60  func WaitForDaemonSetReady(ds *appsv1.DaemonSet, client client.Client, namespace, name string, retryInterval, timeout time.Duration) error {
    61  	err := wait.PollImmediate(retryInterval, timeout, func() (done bool, err error) {
    62  		ctx, cancel := goctx.WithTimeout(goctx.Background(), APITimeout)
    63  		defer cancel()
    64  		err = client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, ds)
    65  		if err != nil {
    66  			if errors.IsNotFound(err) {
    67  				return false, nil
    68  			}
    69  			return false, err
    70  		}
    71  		if ds.Status.DesiredNumberScheduled == ds.Status.NumberReady {
    72  			return true, nil
    73  		} else {
    74  			return false, nil
    75  		}
    76  	})
    77  	if err != nil {
    78  		fmt.Printf("failed to wait for ds %s/%s to be ready: %v", namespace, name, err)
    79  		return err
    80  	}
    81  
    82  	return nil
    83  }
    84  
    85  func WaitForNamespacedObject(obj client.Object, client client.Client, namespace, name string, retryInterval, timeout time.Duration) error {
    86  	err := wait.PollImmediate(retryInterval, timeout, func() (done bool, err error) {
    87  		ctx, cancel := goctx.WithTimeout(goctx.Background(), APITimeout)
    88  		defer cancel()
    89  		err = client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, obj)
    90  		if err != nil {
    91  			if errors.IsNotFound(err) {
    92  				return false, nil
    93  			}
    94  			return false, err
    95  		}
    96  		return true, nil
    97  	})
    98  	if err != nil {
    99  		fmt.Printf("failed to wait for obj %s/%s to exist: %v", namespace, name, err)
   100  		return err
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  func WaitForNamespacedObjectDeleted(obj client.Object, client client.Client, namespace, name string, retryInterval, timeout time.Duration) error {
   107  	err := wait.PollImmediate(retryInterval, timeout, func() (done bool, err error) {
   108  		ctx, cancel := goctx.WithTimeout(goctx.Background(), APITimeout)
   109  		defer cancel()
   110  		err = client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, obj)
   111  		if err != nil {
   112  			if errors.IsNotFound(err) {
   113  				return true, nil
   114  			}
   115  			return false, err
   116  		}
   117  		return false, nil
   118  	})
   119  	if err != nil {
   120  		fmt.Printf("failed to wait for obj %s/%s to not exist: %v", namespace, name, err)
   121  		return err
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func GenerateSriovNetworkCRs(namespace string, specs map[string]sriovnetworkv1.SriovNetworkSpec) map[string]sriovnetworkv1.SriovNetwork {
   128  	crs := make(map[string]sriovnetworkv1.SriovNetwork)
   129  
   130  	for k, v := range specs {
   131  		crs[k] = sriovnetworkv1.SriovNetwork{
   132  			TypeMeta: metav1.TypeMeta{
   133  				Kind:       "SriovNetwork",
   134  				APIVersion: "sriovnetwork.openshift.io/v1",
   135  			},
   136  			ObjectMeta: metav1.ObjectMeta{
   137  				Name:      k,
   138  				Namespace: namespace,
   139  			},
   140  			Spec: v,
   141  		}
   142  	}
   143  	return crs
   144  }
   145  
   146  func GenerateSriovIBNetworkCRs(namespace string, specs map[string]sriovnetworkv1.SriovIBNetworkSpec) map[string]sriovnetworkv1.SriovIBNetwork {
   147  	crs := make(map[string]sriovnetworkv1.SriovIBNetwork)
   148  
   149  	for k, v := range specs {
   150  		crs[k] = sriovnetworkv1.SriovIBNetwork{
   151  			TypeMeta: metav1.TypeMeta{
   152  				Kind:       "SriovIBNetwork",
   153  				APIVersion: "sriovnetwork.openshift.io/v1",
   154  			},
   155  			ObjectMeta: metav1.ObjectMeta{
   156  				Name:      k,
   157  				Namespace: namespace,
   158  			},
   159  			Spec: v,
   160  		}
   161  	}
   162  	return crs
   163  }
   164  
   165  func ValidateDevicePluginConfig(nps []*sriovnetworkv1.SriovNetworkNodePolicy, rawConfig string) error {
   166  	rcl := dptypes.ResourceConfList{}
   167  
   168  	if err := json.Unmarshal([]byte(rawConfig), &rcl); err != nil {
   169  		return err
   170  	}
   171  
   172  	if len(rcl.ResourceList) != 1 {
   173  		return fmt.Errorf("number of resources in config is incorrect: %d", len(rcl.ResourceList))
   174  	}
   175  
   176  	for _, rc := range rcl.ResourceList {
   177  		for _, np := range nps {
   178  			if rc.ResourceName != np.Spec.ResourceName {
   179  				continue
   180  			}
   181  
   182  			netDeviceSelectors := &dptypes.NetDeviceSelectors{}
   183  			raw, err := rc.Selectors.MarshalJSON()
   184  			if err != nil {
   185  				return err
   186  			}
   187  
   188  			err = json.Unmarshal(raw, netDeviceSelectors)
   189  			if err != nil {
   190  				return err
   191  			}
   192  
   193  			if netDeviceSelectors.IsRdma != np.Spec.IsRdma || rc.ResourceName != np.Spec.ResourceName || !validateSelector(netDeviceSelectors, &np.Spec.NicSelector) {
   194  				return fmt.Errorf("content of config is incorrect")
   195  			}
   196  		}
   197  	}
   198  	return nil
   199  }
   200  
   201  func validateSelector(rc *dptypes.NetDeviceSelectors, ns *sriovnetworkv1.SriovNetworkNicSelector) bool {
   202  	if ns.DeviceID != "" {
   203  		if len(rc.Devices) != 1 || ns.DeviceID != rc.Devices[0] {
   204  			return false
   205  		}
   206  	}
   207  	if ns.Vendor != "" {
   208  		if len(rc.Vendors) != 1 || ns.Vendor != rc.Vendors[0] {
   209  			return false
   210  		}
   211  	}
   212  	if len(ns.PfNames) > 0 {
   213  		if !reflect.DeepEqual(ns.PfNames, rc.PfNames) {
   214  			return false
   215  		}
   216  	}
   217  	return true
   218  }