github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/reconciler/reconciler_test.go (about)

     1  package reconciler
     2  
     3  import (
     4  	"testing"
     5  
     6  	"k8s.io/apimachinery/pkg/runtime"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/image"
    10  	"github.com/stretchr/testify/require"
    11  	corev1 "k8s.io/api/core/v1"
    12  	"k8s.io/apimachinery/pkg/api/resource"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/utils/ptr"
    15  
    16  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    17  )
    18  
    19  const workloadUserID = 1001
    20  const defaultPodSecurityConfig = v1alpha1.Restricted
    21  
    22  func TestPodMemoryTarget(t *testing.T) {
    23  	q := resource.MustParse("5Mi")
    24  	var testCases = []struct {
    25  		name     string
    26  		input    *v1alpha1.CatalogSource
    27  		expected *corev1.Pod
    28  	}{
    29  		{
    30  			name: "no memory target set",
    31  			input: &v1alpha1.CatalogSource{
    32  				ObjectMeta: metav1.ObjectMeta{
    33  					Name:      "test",
    34  					Namespace: "testns",
    35  				},
    36  			},
    37  			expected: &corev1.Pod{
    38  				ObjectMeta: metav1.ObjectMeta{
    39  					GenerateName: "test-",
    40  					Namespace:    "testns",
    41  					Labels:       map[string]string{"olm.pod-spec-hash": "8SbHWyYfjbRT8lLcfdZ5ofXNdC1GE6ayztILTF", "olm.managed": "true"},
    42  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
    43  				},
    44  				Spec: corev1.PodSpec{
    45  					Containers: []corev1.Container{
    46  						{
    47  							Name:  "name",
    48  							Image: "image",
    49  							Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
    50  							ReadinessProbe: &corev1.Probe{
    51  								ProbeHandler: corev1.ProbeHandler{
    52  									Exec: &corev1.ExecAction{
    53  										Command: []string{"grpc_health_probe", "-addr=:50051"},
    54  									},
    55  								},
    56  								InitialDelaySeconds: 0,
    57  								TimeoutSeconds:      5,
    58  							},
    59  							LivenessProbe: &corev1.Probe{
    60  								ProbeHandler: corev1.ProbeHandler{
    61  									Exec: &corev1.ExecAction{
    62  										Command: []string{"grpc_health_probe", "-addr=:50051"},
    63  									},
    64  								},
    65  								InitialDelaySeconds: 0,
    66  								TimeoutSeconds:      5,
    67  							},
    68  							StartupProbe: &corev1.Probe{
    69  								ProbeHandler: corev1.ProbeHandler{
    70  									Exec: &corev1.ExecAction{
    71  										Command: []string{"grpc_health_probe", "-addr=:50051"},
    72  									},
    73  								},
    74  								FailureThreshold: 10,
    75  								PeriodSeconds:    10,
    76  								TimeoutSeconds:   5,
    77  							},
    78  							Resources: corev1.ResourceRequirements{
    79  								Requests: corev1.ResourceList{
    80  									corev1.ResourceCPU:    resource.MustParse("10m"),
    81  									corev1.ResourceMemory: resource.MustParse("50Mi"),
    82  								},
    83  							},
    84  							SecurityContext: &corev1.SecurityContext{
    85  								ReadOnlyRootFilesystem: ptr.To(false),
    86  							},
    87  							ImagePullPolicy:          image.InferImagePullPolicy("image"),
    88  							TerminationMessagePolicy: "FallbackToLogsOnError",
    89  						},
    90  					},
    91  					NodeSelector:       map[string]string{"kubernetes.io/os": "linux"},
    92  					ServiceAccountName: "service-account",
    93  				},
    94  			},
    95  		},
    96  		{
    97  			name: "memory target set",
    98  			input: &v1alpha1.CatalogSource{
    99  				ObjectMeta: metav1.ObjectMeta{
   100  					Name:      "test",
   101  					Namespace: "testns",
   102  				},
   103  				Spec: v1alpha1.CatalogSourceSpec{
   104  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   105  						MemoryTarget: &q,
   106  					},
   107  				},
   108  			},
   109  			expected: &corev1.Pod{
   110  				ObjectMeta: metav1.ObjectMeta{
   111  					GenerateName: "test-",
   112  					Namespace:    "testns",
   113  					Labels:       map[string]string{"olm.pod-spec-hash": "3DSBhZZIiOl5YIjTsZy9aRyFIXeDR8mZCGAcYA", "olm.managed": "true"},
   114  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
   115  				},
   116  				Spec: corev1.PodSpec{
   117  					Containers: []corev1.Container{
   118  						{
   119  							Name:  "name",
   120  							Image: "image",
   121  							Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
   122  							Env:   []corev1.EnvVar{{Name: "GOMEMLIMIT", Value: "5MiB"}},
   123  							ReadinessProbe: &corev1.Probe{
   124  								ProbeHandler: corev1.ProbeHandler{
   125  									Exec: &corev1.ExecAction{
   126  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   127  									},
   128  								},
   129  								InitialDelaySeconds: 0,
   130  								TimeoutSeconds:      5,
   131  							},
   132  							LivenessProbe: &corev1.Probe{
   133  								ProbeHandler: corev1.ProbeHandler{
   134  									Exec: &corev1.ExecAction{
   135  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   136  									},
   137  								},
   138  								InitialDelaySeconds: 0,
   139  								TimeoutSeconds:      5,
   140  							},
   141  							StartupProbe: &corev1.Probe{
   142  								ProbeHandler: corev1.ProbeHandler{
   143  									Exec: &corev1.ExecAction{
   144  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   145  									},
   146  								},
   147  								FailureThreshold: 10,
   148  								PeriodSeconds:    10,
   149  								TimeoutSeconds:   5,
   150  							},
   151  							Resources: corev1.ResourceRequirements{
   152  								Requests: corev1.ResourceList{
   153  									corev1.ResourceCPU:    resource.MustParse("10m"),
   154  									corev1.ResourceMemory: resource.MustParse("5Mi"),
   155  								},
   156  								Limits: corev1.ResourceList{},
   157  							},
   158  							SecurityContext: &corev1.SecurityContext{
   159  								ReadOnlyRootFilesystem: ptr.To(false),
   160  							},
   161  							ImagePullPolicy:          image.InferImagePullPolicy("image"),
   162  							TerminationMessagePolicy: "FallbackToLogsOnError",
   163  						},
   164  					},
   165  					NodeSelector:       map[string]string{"kubernetes.io/os": "linux"},
   166  					ServiceAccountName: "service-account",
   167  				},
   168  			},
   169  		},
   170  	}
   171  
   172  	for _, testCase := range testCases {
   173  		t.Run(testCase.name, func(t *testing.T) {
   174  			pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
   175  			require.NoError(t, err)
   176  			if diff := cmp.Diff(pod, testCase.expected); diff != "" {
   177  				t.Errorf("got incorrect pod: %v", diff)
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  func serviceAccount(namespace, name string) *corev1.ServiceAccount {
   184  	return &corev1.ServiceAccount{
   185  		ObjectMeta: metav1.ObjectMeta{
   186  			Namespace: namespace,
   187  			Name:      name,
   188  		},
   189  	}
   190  }
   191  
   192  func TestPodExtractContent(t *testing.T) {
   193  	var testCases = []struct {
   194  		name                  string
   195  		input                 *v1alpha1.CatalogSource
   196  		securityContextConfig v1alpha1.SecurityConfig
   197  		expected              *corev1.Pod
   198  	}{
   199  		{
   200  			name: "content extraction not requested - legacy security context config",
   201  			input: &v1alpha1.CatalogSource{
   202  				ObjectMeta: metav1.ObjectMeta{
   203  					Name:      "test",
   204  					Namespace: "testns",
   205  				},
   206  			},
   207  			securityContextConfig: v1alpha1.Legacy,
   208  			expected: &corev1.Pod{
   209  				ObjectMeta: metav1.ObjectMeta{
   210  					GenerateName: "test-",
   211  					Namespace:    "testns",
   212  					Labels:       map[string]string{"olm.pod-spec-hash": "8SbHWyYfjbRT8lLcfdZ5ofXNdC1GE6ayztILTF", "olm.managed": "true"},
   213  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
   214  				},
   215  				Spec: corev1.PodSpec{
   216  					Containers: []corev1.Container{
   217  						{
   218  							Name:  "name",
   219  							Image: "image",
   220  							Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
   221  							ReadinessProbe: &corev1.Probe{
   222  								ProbeHandler: corev1.ProbeHandler{
   223  									Exec: &corev1.ExecAction{
   224  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   225  									},
   226  								},
   227  								InitialDelaySeconds: 0,
   228  								TimeoutSeconds:      5,
   229  							},
   230  							LivenessProbe: &corev1.Probe{
   231  								ProbeHandler: corev1.ProbeHandler{
   232  									Exec: &corev1.ExecAction{
   233  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   234  									},
   235  								},
   236  								InitialDelaySeconds: 0,
   237  								TimeoutSeconds:      5,
   238  							},
   239  							StartupProbe: &corev1.Probe{
   240  								ProbeHandler: corev1.ProbeHandler{
   241  									Exec: &corev1.ExecAction{
   242  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   243  									},
   244  								},
   245  								FailureThreshold: 10,
   246  								PeriodSeconds:    10,
   247  								TimeoutSeconds:   5,
   248  							},
   249  							Resources: corev1.ResourceRequirements{
   250  								Requests: corev1.ResourceList{
   251  									corev1.ResourceCPU:    resource.MustParse("10m"),
   252  									corev1.ResourceMemory: resource.MustParse("50Mi"),
   253  								},
   254  							},
   255  							SecurityContext: &corev1.SecurityContext{
   256  								ReadOnlyRootFilesystem: ptr.To(false),
   257  							},
   258  							ImagePullPolicy:          image.InferImagePullPolicy("image"),
   259  							TerminationMessagePolicy: "FallbackToLogsOnError",
   260  						},
   261  					},
   262  					NodeSelector:       map[string]string{"kubernetes.io/os": "linux"},
   263  					ServiceAccountName: "service-account",
   264  				},
   265  			},
   266  		},
   267  		{
   268  			name: "content extraction expected - legacy security context config",
   269  			input: &v1alpha1.CatalogSource{
   270  				ObjectMeta: metav1.ObjectMeta{
   271  					Name:      "test",
   272  					Namespace: "testns",
   273  				},
   274  				Spec: v1alpha1.CatalogSourceSpec{
   275  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   276  						ExtractContent: &v1alpha1.ExtractContentConfig{
   277  							CacheDir:   "/tmp/cache",
   278  							CatalogDir: "/catalog",
   279  						},
   280  					},
   281  				},
   282  			},
   283  			securityContextConfig: v1alpha1.Legacy,
   284  			expected: &corev1.Pod{
   285  				ObjectMeta: metav1.ObjectMeta{
   286  					GenerateName: "test-",
   287  					Namespace:    "testns",
   288  					Labels:       map[string]string{"olm.pod-spec-hash": "5MSUJs07MqD3fl9supmPaRNxD9N6tK8Bjo4OFl", "olm.managed": "true"},
   289  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
   290  				},
   291  				Spec: corev1.PodSpec{
   292  					Volumes: []corev1.Volume{
   293  						{
   294  							Name:         "utilities",
   295  							VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
   296  						},
   297  						{
   298  							Name:         "catalog-content",
   299  							VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
   300  						},
   301  					},
   302  					InitContainers: []corev1.Container{
   303  						{
   304  							Name:                     "extract-utilities",
   305  							Image:                    "utilImage",
   306  							Command:                  []string{"cp"},
   307  							Args:                     []string{"/bin/copy-content", "/utilities/copy-content"},
   308  							VolumeMounts:             []corev1.VolumeMount{{Name: "utilities", MountPath: "/utilities"}},
   309  							TerminationMessagePolicy: "FallbackToLogsOnError",
   310  						},
   311  						{
   312  							Name:            "extract-content",
   313  							Image:           "image",
   314  							ImagePullPolicy: image.InferImagePullPolicy("image"),
   315  							Command:         []string{"/utilities/copy-content"},
   316  							Args: []string{
   317  								"--catalog.from=/catalog",
   318  								"--catalog.to=/extracted-catalog/catalog",
   319  								"--cache.from=/tmp/cache",
   320  								"--cache.to=/extracted-catalog/cache",
   321  							},
   322  							VolumeMounts: []corev1.VolumeMount{
   323  								{Name: "utilities", MountPath: "/utilities"},
   324  								{Name: "catalog-content", MountPath: "/extracted-catalog"},
   325  							},
   326  							TerminationMessagePolicy: "FallbackToLogsOnError",
   327  						},
   328  					},
   329  					Containers: []corev1.Container{
   330  						{
   331  							Name:    "name",
   332  							Image:   "opmImage",
   333  							Command: []string{"/bin/opm"},
   334  							Args:    []string{"serve", "/extracted-catalog/catalog", "--cache-dir=/extracted-catalog/cache"},
   335  							Ports:   []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
   336  							ReadinessProbe: &corev1.Probe{
   337  								ProbeHandler: corev1.ProbeHandler{
   338  									Exec: &corev1.ExecAction{
   339  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   340  									},
   341  								},
   342  								InitialDelaySeconds: 0,
   343  								TimeoutSeconds:      5,
   344  							},
   345  							LivenessProbe: &corev1.Probe{
   346  								ProbeHandler: corev1.ProbeHandler{
   347  									Exec: &corev1.ExecAction{
   348  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   349  									},
   350  								},
   351  								InitialDelaySeconds: 0,
   352  								TimeoutSeconds:      5,
   353  							},
   354  							StartupProbe: &corev1.Probe{
   355  								ProbeHandler: corev1.ProbeHandler{
   356  									Exec: &corev1.ExecAction{
   357  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   358  									},
   359  								},
   360  								FailureThreshold: 10,
   361  								PeriodSeconds:    10,
   362  								TimeoutSeconds:   5,
   363  							},
   364  							Resources: corev1.ResourceRequirements{
   365  								Requests: corev1.ResourceList{
   366  									corev1.ResourceCPU:    resource.MustParse("10m"),
   367  									corev1.ResourceMemory: resource.MustParse("50Mi"),
   368  								},
   369  							},
   370  							SecurityContext: &corev1.SecurityContext{
   371  								ReadOnlyRootFilesystem: ptr.To(false),
   372  							},
   373  							ImagePullPolicy:          image.InferImagePullPolicy("image"),
   374  							TerminationMessagePolicy: "FallbackToLogsOnError",
   375  							VolumeMounts:             []corev1.VolumeMount{{Name: "catalog-content", MountPath: "/extracted-catalog"}},
   376  						},
   377  					},
   378  					NodeSelector:       map[string]string{"kubernetes.io/os": "linux"},
   379  					ServiceAccountName: "service-account",
   380  				},
   381  			},
   382  		},
   383  		{
   384  			name: "content extraction not requested - restricted security context config",
   385  			input: &v1alpha1.CatalogSource{
   386  				ObjectMeta: metav1.ObjectMeta{
   387  					Name:      "test",
   388  					Namespace: "testns",
   389  				},
   390  			},
   391  			securityContextConfig: v1alpha1.Restricted,
   392  			expected: &corev1.Pod{
   393  				ObjectMeta: metav1.ObjectMeta{
   394  					GenerateName: "test-",
   395  					Namespace:    "testns",
   396  					Labels:       map[string]string{"olm.pod-spec-hash": "3sDLk8MMNptrqUfdnruY2gUi1g8O4wpMWC6Q52", "olm.managed": "true"},
   397  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
   398  				},
   399  				Spec: corev1.PodSpec{
   400  					Containers: []corev1.Container{
   401  						{
   402  							Name:  "name",
   403  							Image: "image",
   404  							Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
   405  							ReadinessProbe: &corev1.Probe{
   406  								ProbeHandler: corev1.ProbeHandler{
   407  									Exec: &corev1.ExecAction{
   408  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   409  									},
   410  								},
   411  								InitialDelaySeconds: 0,
   412  								TimeoutSeconds:      5,
   413  							},
   414  							LivenessProbe: &corev1.Probe{
   415  								ProbeHandler: corev1.ProbeHandler{
   416  									Exec: &corev1.ExecAction{
   417  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   418  									},
   419  								},
   420  								InitialDelaySeconds: 0,
   421  								TimeoutSeconds:      5,
   422  							},
   423  							StartupProbe: &corev1.Probe{
   424  								ProbeHandler: corev1.ProbeHandler{
   425  									Exec: &corev1.ExecAction{
   426  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   427  									},
   428  								},
   429  								FailureThreshold: 10,
   430  								PeriodSeconds:    10,
   431  								TimeoutSeconds:   5,
   432  							},
   433  							Resources: corev1.ResourceRequirements{
   434  								Requests: corev1.ResourceList{
   435  									corev1.ResourceCPU:    resource.MustParse("10m"),
   436  									corev1.ResourceMemory: resource.MustParse("50Mi"),
   437  								},
   438  							},
   439  							ImagePullPolicy: image.InferImagePullPolicy("image"),
   440  							SecurityContext: &corev1.SecurityContext{
   441  								Capabilities:             &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
   442  								AllowPrivilegeEscalation: ptr.To(false),
   443  								ReadOnlyRootFilesystem:   ptr.To(false),
   444  							},
   445  							TerminationMessagePolicy: "FallbackToLogsOnError",
   446  						},
   447  					},
   448  					NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
   449  					SecurityContext: &corev1.PodSecurityContext{
   450  						RunAsUser:      ptr.To(int64(workloadUserID)),
   451  						RunAsNonRoot:   ptr.To(true),
   452  						SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
   453  					},
   454  					ServiceAccountName: "service-account",
   455  				},
   456  			},
   457  		},
   458  		{
   459  			name: "content extraction expected - restricted security context config",
   460  			input: &v1alpha1.CatalogSource{
   461  				ObjectMeta: metav1.ObjectMeta{
   462  					Name:      "test",
   463  					Namespace: "testns",
   464  				},
   465  				Spec: v1alpha1.CatalogSourceSpec{
   466  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   467  						ExtractContent: &v1alpha1.ExtractContentConfig{
   468  							CacheDir:   "/tmp/cache",
   469  							CatalogDir: "/catalog",
   470  						},
   471  					},
   472  				},
   473  			},
   474  			securityContextConfig: v1alpha1.Restricted,
   475  			expected: &corev1.Pod{
   476  				ObjectMeta: metav1.ObjectMeta{
   477  					GenerateName: "test-",
   478  					Namespace:    "testns",
   479  					Labels:       map[string]string{"olm.pod-spec-hash": "1X4YqbfXuc9SB9ztW03WNOyanr9aIhKfijeBHH", "olm.managed": "true"},
   480  					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
   481  				},
   482  				Spec: corev1.PodSpec{
   483  					Volumes: []corev1.Volume{
   484  						{
   485  							Name:         "utilities",
   486  							VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
   487  						},
   488  						{
   489  							Name:         "catalog-content",
   490  							VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
   491  						},
   492  					},
   493  					InitContainers: []corev1.Container{
   494  						{
   495  							Name:    "extract-utilities",
   496  							Image:   "utilImage",
   497  							Command: []string{"cp"},
   498  							Args:    []string{"/bin/copy-content", "/utilities/copy-content"},
   499  							SecurityContext: &corev1.SecurityContext{
   500  								Capabilities:             &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
   501  								AllowPrivilegeEscalation: ptr.To(false),
   502  							},
   503  							VolumeMounts:             []corev1.VolumeMount{{Name: "utilities", MountPath: "/utilities"}},
   504  							TerminationMessagePolicy: "FallbackToLogsOnError",
   505  						},
   506  						{
   507  							Name:            "extract-content",
   508  							Image:           "image",
   509  							ImagePullPolicy: image.InferImagePullPolicy("image"),
   510  							Command:         []string{"/utilities/copy-content"},
   511  							Args: []string{
   512  								"--catalog.from=/catalog",
   513  								"--catalog.to=/extracted-catalog/catalog",
   514  								"--cache.from=/tmp/cache",
   515  								"--cache.to=/extracted-catalog/cache",
   516  							},
   517  							SecurityContext: &corev1.SecurityContext{
   518  								Capabilities:             &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
   519  								AllowPrivilegeEscalation: ptr.To(false),
   520  							},
   521  							VolumeMounts: []corev1.VolumeMount{
   522  								{Name: "utilities", MountPath: "/utilities"},
   523  								{Name: "catalog-content", MountPath: "/extracted-catalog"},
   524  							},
   525  							TerminationMessagePolicy: "FallbackToLogsOnError",
   526  						},
   527  					},
   528  					Containers: []corev1.Container{
   529  						{
   530  							Name:    "name",
   531  							Image:   "opmImage",
   532  							Command: []string{"/bin/opm"},
   533  							Args:    []string{"serve", "/extracted-catalog/catalog", "--cache-dir=/extracted-catalog/cache"},
   534  							Ports:   []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
   535  							ReadinessProbe: &corev1.Probe{
   536  								ProbeHandler: corev1.ProbeHandler{
   537  									Exec: &corev1.ExecAction{
   538  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   539  									},
   540  								},
   541  								InitialDelaySeconds: 0,
   542  								TimeoutSeconds:      5,
   543  							},
   544  							LivenessProbe: &corev1.Probe{
   545  								ProbeHandler: corev1.ProbeHandler{
   546  									Exec: &corev1.ExecAction{
   547  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   548  									},
   549  								},
   550  								InitialDelaySeconds: 0,
   551  								TimeoutSeconds:      5,
   552  							},
   553  							StartupProbe: &corev1.Probe{
   554  								ProbeHandler: corev1.ProbeHandler{
   555  									Exec: &corev1.ExecAction{
   556  										Command: []string{"grpc_health_probe", "-addr=:50051"},
   557  									},
   558  								},
   559  								FailureThreshold: 10,
   560  								PeriodSeconds:    10,
   561  								TimeoutSeconds:   5,
   562  							},
   563  							Resources: corev1.ResourceRequirements{
   564  								Requests: corev1.ResourceList{
   565  									corev1.ResourceCPU:    resource.MustParse("10m"),
   566  									corev1.ResourceMemory: resource.MustParse("50Mi"),
   567  								},
   568  							},
   569  							ImagePullPolicy: image.InferImagePullPolicy("image"),
   570  							SecurityContext: &corev1.SecurityContext{
   571  								Capabilities:             &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
   572  								AllowPrivilegeEscalation: ptr.To(false),
   573  								ReadOnlyRootFilesystem:   ptr.To(false),
   574  							},
   575  							TerminationMessagePolicy: "FallbackToLogsOnError",
   576  							VolumeMounts:             []corev1.VolumeMount{{Name: "catalog-content", MountPath: "/extracted-catalog"}},
   577  						},
   578  					},
   579  					NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
   580  					SecurityContext: &corev1.PodSecurityContext{
   581  						RunAsUser:      ptr.To(int64(workloadUserID)),
   582  						RunAsNonRoot:   ptr.To(true),
   583  						SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
   584  					},
   585  					ServiceAccountName: "service-account",
   586  				},
   587  			},
   588  		},
   589  	}
   590  
   591  	for _, testCase := range testCases {
   592  		t.Run(testCase.name, func(t *testing.T) {
   593  			pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), testCase.securityContextConfig)
   594  			require.NoError(t, err)
   595  			if diff := cmp.Diff(testCase.expected, pod); diff != "" {
   596  				t.Errorf("got incorrect pod: %v", diff)
   597  			}
   598  		})
   599  	}
   600  }
   601  
   602  func TestPodServiceAccountImagePullSecrets(t *testing.T) {
   603  	var testCases = []struct {
   604  		name           string
   605  		catalogSource  *v1alpha1.CatalogSource
   606  		serviceAccount *corev1.ServiceAccount
   607  	}{
   608  		{
   609  			name: "ServiceAccount has no imagePullSecret",
   610  			serviceAccount: &corev1.ServiceAccount{
   611  				ObjectMeta: metav1.ObjectMeta{
   612  					Namespace: "",
   613  					Name:      "service-account",
   614  				},
   615  			},
   616  		},
   617  		{
   618  			name: "ServiceAccount has one imagePullSecret",
   619  			serviceAccount: &corev1.ServiceAccount{
   620  				ObjectMeta: metav1.ObjectMeta{
   621  					Namespace: "",
   622  					Name:      "service-account",
   623  				},
   624  				ImagePullSecrets: []corev1.LocalObjectReference{{Name: "foo"}},
   625  			},
   626  		},
   627  	}
   628  
   629  	catalogSource := &v1alpha1.CatalogSource{
   630  		ObjectMeta: metav1.ObjectMeta{
   631  			Name:      "test",
   632  			Namespace: "testns",
   633  		},
   634  		Spec: v1alpha1.CatalogSourceSpec{
   635  			GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   636  				ExtractContent: &v1alpha1.ExtractContentConfig{
   637  					CacheDir:   "/tmp/cache",
   638  					CatalogDir: "/catalog",
   639  				},
   640  			},
   641  		},
   642  	}
   643  
   644  	for _, testCase := range testCases {
   645  		pod, err := Pod(catalogSource, "name", "opmImage", "utilImage", "image", testCase.serviceAccount, map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
   646  		require.NoError(t, err)
   647  		if diff := cmp.Diff(testCase.serviceAccount.ImagePullSecrets, pod.Spec.ImagePullSecrets); diff != "" {
   648  			t.Errorf("got incorrect pod: %v", diff)
   649  		}
   650  	}
   651  }
   652  
   653  func TestPodNodeSelector(t *testing.T) {
   654  	catsrc := &v1alpha1.CatalogSource{
   655  		ObjectMeta: metav1.ObjectMeta{
   656  			Name:      "test",
   657  			Namespace: "testns",
   658  		},
   659  	}
   660  
   661  	key := "kubernetes.io/os"
   662  	value := "linux"
   663  
   664  	gotCatSrcPod, err := Pod(catsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
   665  	require.NoError(t, err)
   666  	gotCatSrcPodSelector := gotCatSrcPod.Spec.NodeSelector
   667  
   668  	if gotCatSrcPodSelector[key] != value {
   669  		t.Errorf("expected %s value for node selector key %s, received %s value instead", value, key,
   670  			gotCatSrcPodSelector[key])
   671  	}
   672  }
   673  
   674  func TestPullPolicy(t *testing.T) {
   675  	var table = []struct {
   676  		image  string
   677  		policy corev1.PullPolicy
   678  	}{
   679  		{
   680  			image:  "quay.io/operator-framework/olm@sha256:b9d011c0fbfb65b387904f8fafc47ee1a9479d28d395473341288ee126ed993b",
   681  			policy: corev1.PullIfNotPresent,
   682  		},
   683  		{
   684  			image:  "gcc@sha256:06a6f170d7fff592e44b089c0d2e68d870573eb9a23d9c66d4b6ea11f8fad18b",
   685  			policy: corev1.PullIfNotPresent,
   686  		},
   687  		{
   688  			image:  "myimage:1.0",
   689  			policy: corev1.PullAlways,
   690  		},
   691  		{
   692  			image:  "busybox",
   693  			policy: corev1.PullAlways,
   694  		},
   695  		{
   696  			image:  "gcc@sha256:06a6f170d7fff592e44b089c0d2e68",
   697  			policy: corev1.PullIfNotPresent,
   698  		},
   699  		{
   700  			image:  "hello@md5:b1946ac92492d2347c6235b4d2611184",
   701  			policy: corev1.PullIfNotPresent,
   702  		},
   703  	}
   704  
   705  	source := &v1alpha1.CatalogSource{
   706  		ObjectMeta: metav1.ObjectMeta{
   707  			Name:      "test",
   708  			Namespace: "test-ns",
   709  		},
   710  	}
   711  
   712  	for _, tt := range table {
   713  		p, err := Pod(source, "catalog", "opmImage", "utilImage", tt.image, serviceAccount("", "service-account"), nil, nil, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
   714  		require.NoError(t, err)
   715  		policy := p.Spec.Containers[0].ImagePullPolicy
   716  		if policy != tt.policy {
   717  			t.Fatalf("expected pull policy %s for image  %s", tt.policy, tt.image)
   718  		}
   719  	}
   720  }
   721  
   722  func TestPodContainerSecurityContext(t *testing.T) {
   723  	testcases := []struct {
   724  		title                            string
   725  		inputCatsrc                      *v1alpha1.CatalogSource
   726  		namespacePodSecurityConfig       v1alpha1.SecurityConfig
   727  		expectedSecurityContext          *corev1.PodSecurityContext
   728  		expectedContainerSecurityContext *corev1.SecurityContext
   729  	}{
   730  		{
   731  			title: "NoSpecDefined/NamespaceRestricted/UseRestricted",
   732  			inputCatsrc: &v1alpha1.CatalogSource{
   733  				ObjectMeta: metav1.ObjectMeta{
   734  					Name:      "test",
   735  					Namespace: testNamespace,
   736  				},
   737  			},
   738  			namespacePodSecurityConfig: v1alpha1.Restricted,
   739  			expectedContainerSecurityContext: &corev1.SecurityContext{
   740  				AllowPrivilegeEscalation: ptr.To(false),
   741  				Capabilities: &corev1.Capabilities{
   742  					Drop: []corev1.Capability{"ALL"},
   743  				},
   744  				ReadOnlyRootFilesystem: ptr.To(false), // Reflecting expected 'restricted' settings
   745  			},
   746  			expectedSecurityContext: &corev1.PodSecurityContext{
   747  				SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
   748  				RunAsNonRoot:   ptr.To(true),
   749  				RunAsUser:      ptr.To(int64(workloadUserID)),
   750  			},
   751  		},
   752  		{
   753  			title:                      "NoSpecDefined/NamespaceNotRestricted/UseLegacy",
   754  			namespacePodSecurityConfig: v1alpha1.Legacy,
   755  			inputCatsrc: &v1alpha1.CatalogSource{
   756  				ObjectMeta: metav1.ObjectMeta{
   757  					Name:      "test",
   758  					Namespace: testNamespace,
   759  				},
   760  			},
   761  			expectedContainerSecurityContext: &corev1.SecurityContext{ReadOnlyRootFilesystem: ptr.To(false)},
   762  			expectedSecurityContext:          nil,
   763  		},
   764  		{
   765  			title: "SpecDefined/NoGRPCPodConfig/NamespaceRestricted/UseRestricted",
   766  			inputCatsrc: &v1alpha1.CatalogSource{
   767  				ObjectMeta: metav1.ObjectMeta{
   768  					Name:      "test",
   769  					Namespace: testNamespace,
   770  				},
   771  				Spec: v1alpha1.CatalogSourceSpec{},
   772  			},
   773  			namespacePodSecurityConfig: v1alpha1.Restricted,
   774  			expectedContainerSecurityContext: &corev1.SecurityContext{
   775  				AllowPrivilegeEscalation: ptr.To(false),
   776  				Capabilities: &corev1.Capabilities{
   777  					Drop: []corev1.Capability{"ALL"},
   778  				},
   779  				ReadOnlyRootFilesystem: ptr.To(false),
   780  			},
   781  			expectedSecurityContext: &corev1.PodSecurityContext{
   782  				SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
   783  				RunAsNonRoot:   ptr.To(true),
   784  				RunAsUser:      ptr.To(int64(workloadUserID)),
   785  			},
   786  		},
   787  		{
   788  			title: "SpecDefined/NoGRPCPodConfig/NamespaceNotRestricted/UseLegacy",
   789  			inputCatsrc: &v1alpha1.CatalogSource{
   790  				ObjectMeta: metav1.ObjectMeta{
   791  					Name:      "test",
   792  					Namespace: testNamespace,
   793  				},
   794  				Spec: v1alpha1.CatalogSourceSpec{
   795  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{},
   796  				},
   797  			},
   798  			namespacePodSecurityConfig:       v1alpha1.Legacy,
   799  			expectedContainerSecurityContext: &corev1.SecurityContext{ReadOnlyRootFilesystem: ptr.To(false)},
   800  			expectedSecurityContext:          nil,
   801  		},
   802  		{
   803  			title: "SpecDefined/SecurityContextConfig:Legacy/NoChangeExpected",
   804  			inputCatsrc: &v1alpha1.CatalogSource{
   805  				ObjectMeta: metav1.ObjectMeta{
   806  					Name:      "test",
   807  					Namespace: testNamespace,
   808  				},
   809  				Spec: v1alpha1.CatalogSourceSpec{
   810  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   811  						SecurityContextConfig: v1alpha1.Legacy,
   812  					},
   813  				},
   814  			},
   815  			namespacePodSecurityConfig:       v1alpha1.Restricted, // set to the opposite of the config to catch possible errors
   816  			expectedContainerSecurityContext: &corev1.SecurityContext{ReadOnlyRootFilesystem: ptr.To(false)},
   817  			expectedSecurityContext:          nil,
   818  		},
   819  		{
   820  			title: "SpecDefined/SecurityContextConfig:Restricted/RestrictedSecurityConfigApplied",
   821  			inputCatsrc: &v1alpha1.CatalogSource{
   822  				ObjectMeta: metav1.ObjectMeta{
   823  					Name:      "test",
   824  					Namespace: testNamespace,
   825  				},
   826  				Spec: v1alpha1.CatalogSourceSpec{
   827  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   828  						SecurityContextConfig: v1alpha1.Restricted,
   829  					},
   830  				},
   831  			},
   832  			namespacePodSecurityConfig: v1alpha1.Legacy, // set to the opposite of the config to catch possible errors
   833  			expectedContainerSecurityContext: &corev1.SecurityContext{
   834  				ReadOnlyRootFilesystem:   ptr.To(false),
   835  				AllowPrivilegeEscalation: ptr.To(false),
   836  				Capabilities: &corev1.Capabilities{
   837  					Drop: []corev1.Capability{"ALL"},
   838  				},
   839  			},
   840  			expectedSecurityContext: &corev1.PodSecurityContext{
   841  				SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
   842  				RunAsNonRoot:   ptr.To(true),
   843  				RunAsUser:      ptr.To(int64(workloadUserID)),
   844  			},
   845  		},
   846  	}
   847  
   848  	for _, testcase := range testcases {
   849  		t.Run(testcase.title, func(t *testing.T) {
   850  			outputPod, err := Pod(testcase.inputCatsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), workloadUserID, testcase.namespacePodSecurityConfig)
   851  			require.NoError(t, err)
   852  
   853  			// Assert PodSecurityContext
   854  			require.Equal(t, testcase.expectedSecurityContext, outputPod.Spec.SecurityContext)
   855  
   856  			// Assert ContainerSecurityContext
   857  			require.Equal(t, testcase.expectedContainerSecurityContext, outputPod.Spec.Containers[0].SecurityContext)
   858  		})
   859  	}
   860  }
   861  
   862  // TestPodAvoidsConcurrentWrite is a regression test for
   863  // https://bugzilla.redhat.com/show_bug.cgi?id=2101357
   864  // we were mutating the input annotations and labels parameters causing
   865  // concurrent write issues
   866  func TestPodAvoidsConcurrentWrite(t *testing.T) {
   867  	catsrc := &v1alpha1.CatalogSource{
   868  		ObjectMeta: metav1.ObjectMeta{
   869  			Name:      "test",
   870  			Namespace: "testns",
   871  		},
   872  	}
   873  
   874  	labels := map[string]string{
   875  		"label": "something",
   876  	}
   877  
   878  	annotations := map[string]string{
   879  		"annotation": "somethingelse",
   880  	}
   881  
   882  	gotPod, err := Pod(catsrc, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), labels, annotations, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
   883  	require.NoError(t, err)
   884  
   885  	// check labels and annotations point to different addresses between parameters and what's in the pod
   886  	require.NotEqual(t, &labels, &gotPod.Labels)
   887  	require.NotEqual(t, &annotations, &gotPod.Annotations)
   888  
   889  	// check that labels and annotations from the parameters were copied down to the pod's
   890  	require.Equal(t, labels["label"], gotPod.Labels["label"])
   891  	require.Equal(t, annotations["annotation"], gotPod.Annotations["annotation"])
   892  }
   893  
   894  func TestPodSchedulingOverrides(t *testing.T) {
   895  	// This test ensures that any overriding pod scheduling configuration elements
   896  	// defined in spec.grpcPodConfig are applied to the catalog source pod created
   897  	// when spec.sourceType = 'grpc' and spec.image is set.
   898  	var tolerationSeconds int64 = 120
   899  	var overriddenPriorityClassName = "some-prio-class"
   900  	var overriddenNodeSelectors = map[string]string{
   901  		"label":  "value",
   902  		"label2": "value2",
   903  	}
   904  	var defaultNodeSelectors = map[string]string{
   905  		"kubernetes.io/os": "linux",
   906  	}
   907  	var defaultPriorityClassName = ""
   908  
   909  	var overriddenTolerations = []corev1.Toleration{
   910  		{
   911  			Key:               "some/key",
   912  			Operator:          corev1.TolerationOpExists,
   913  			Effect:            corev1.TaintEffectNoExecute,
   914  			TolerationSeconds: &tolerationSeconds,
   915  		},
   916  		{
   917  			Key:      "someother/key",
   918  			Operator: corev1.TolerationOpEqual,
   919  			Effect:   corev1.TaintEffectNoSchedule,
   920  		},
   921  	}
   922  
   923  	var overriddenAffinity = &corev1.Affinity{
   924  		NodeAffinity: &corev1.NodeAffinity{
   925  			RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
   926  				NodeSelectorTerms: []corev1.NodeSelectorTerm{
   927  					{
   928  						MatchExpressions: []corev1.NodeSelectorRequirement{
   929  							{
   930  								Key:      "kubernetes.io/arch",
   931  								Operator: corev1.NodeSelectorOpIn,
   932  								Values: []string{
   933  									"amd64",
   934  									"arm",
   935  								},
   936  							},
   937  						},
   938  					},
   939  				},
   940  			},
   941  		},
   942  	}
   943  
   944  	testCases := []struct {
   945  		title                     string
   946  		catalogSource             *v1alpha1.CatalogSource
   947  		expectedNodeSelectors     map[string]string
   948  		expectedTolerations       []corev1.Toleration
   949  		expectedAffinity          *corev1.Affinity
   950  		expectedPriorityClassName string
   951  		annotations               map[string]string
   952  	}{
   953  		{
   954  			title: "no overrides",
   955  			catalogSource: &v1alpha1.CatalogSource{
   956  				ObjectMeta: metav1.ObjectMeta{
   957  					Name:      "test",
   958  					Namespace: "testns",
   959  				},
   960  				Spec: v1alpha1.CatalogSourceSpec{
   961  					SourceType: v1alpha1.SourceTypeGrpc,
   962  					Image:      "repo/image:tag",
   963  				},
   964  			},
   965  			expectedTolerations:       nil,
   966  			expectedAffinity:          nil,
   967  			expectedPriorityClassName: defaultPriorityClassName,
   968  			expectedNodeSelectors:     defaultNodeSelectors,
   969  		}, {
   970  			title: "override node selectors",
   971  			catalogSource: &v1alpha1.CatalogSource{
   972  				ObjectMeta: metav1.ObjectMeta{
   973  					Name:      "test",
   974  					Namespace: "testns",
   975  				},
   976  				Spec: v1alpha1.CatalogSourceSpec{
   977  					SourceType: v1alpha1.SourceTypeGrpc,
   978  					Image:      "repo/image:tag",
   979  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   980  						NodeSelector: overriddenNodeSelectors,
   981  					},
   982  				},
   983  			},
   984  			expectedTolerations:       nil,
   985  			expectedAffinity:          nil,
   986  			expectedPriorityClassName: defaultPriorityClassName,
   987  			expectedNodeSelectors:     overriddenNodeSelectors,
   988  		}, {
   989  			title: "override priority class name",
   990  			catalogSource: &v1alpha1.CatalogSource{
   991  				ObjectMeta: metav1.ObjectMeta{
   992  					Name:      "test",
   993  					Namespace: "testns",
   994  				},
   995  				Spec: v1alpha1.CatalogSourceSpec{
   996  					SourceType: v1alpha1.SourceTypeGrpc,
   997  					Image:      "repo/image:tag",
   998  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
   999  						PriorityClassName: &overriddenPriorityClassName,
  1000  					},
  1001  				},
  1002  			},
  1003  			expectedTolerations:       nil,
  1004  			expectedAffinity:          nil,
  1005  			expectedPriorityClassName: overriddenPriorityClassName,
  1006  			expectedNodeSelectors:     defaultNodeSelectors,
  1007  		}, {
  1008  			title: "doesn't override priority class name when its nil",
  1009  			catalogSource: &v1alpha1.CatalogSource{
  1010  				ObjectMeta: metav1.ObjectMeta{
  1011  					Name:      "test",
  1012  					Namespace: "testns",
  1013  				},
  1014  				Spec: v1alpha1.CatalogSourceSpec{
  1015  					SourceType: v1alpha1.SourceTypeGrpc,
  1016  					Image:      "repo/image:tag",
  1017  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
  1018  						PriorityClassName: nil,
  1019  					},
  1020  				},
  1021  			},
  1022  			expectedTolerations:       nil,
  1023  			expectedAffinity:          nil,
  1024  			expectedPriorityClassName: defaultPriorityClassName,
  1025  			expectedNodeSelectors:     defaultNodeSelectors,
  1026  		}, {
  1027  			title: "Override node tolerations",
  1028  			catalogSource: &v1alpha1.CatalogSource{
  1029  				ObjectMeta: metav1.ObjectMeta{
  1030  					Name:      "test",
  1031  					Namespace: "testns",
  1032  				},
  1033  				Spec: v1alpha1.CatalogSourceSpec{
  1034  					SourceType: v1alpha1.SourceTypeGrpc,
  1035  					Image:      "repo/image:tag",
  1036  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
  1037  						Tolerations: overriddenTolerations,
  1038  					},
  1039  				},
  1040  			},
  1041  			expectedTolerations:       overriddenTolerations,
  1042  			expectedAffinity:          nil,
  1043  			expectedPriorityClassName: defaultPriorityClassName,
  1044  			expectedNodeSelectors:     defaultNodeSelectors,
  1045  		}, {
  1046  			title: "Override affinity",
  1047  			catalogSource: &v1alpha1.CatalogSource{
  1048  				ObjectMeta: metav1.ObjectMeta{
  1049  					Name:      "test",
  1050  					Namespace: "testns",
  1051  				},
  1052  				Spec: v1alpha1.CatalogSourceSpec{
  1053  					SourceType: v1alpha1.SourceTypeGrpc,
  1054  					Image:      "repo/image:tag",
  1055  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
  1056  						Affinity: overriddenAffinity,
  1057  					},
  1058  				},
  1059  			},
  1060  			expectedTolerations:       nil,
  1061  			expectedAffinity:          overriddenAffinity,
  1062  			expectedPriorityClassName: defaultPriorityClassName,
  1063  			expectedNodeSelectors:     defaultNodeSelectors,
  1064  		}, {
  1065  			title: "Override all the things",
  1066  			catalogSource: &v1alpha1.CatalogSource{
  1067  				ObjectMeta: metav1.ObjectMeta{
  1068  					Name:      "test",
  1069  					Namespace: "testns",
  1070  				},
  1071  				Spec: v1alpha1.CatalogSourceSpec{
  1072  					SourceType: v1alpha1.SourceTypeGrpc,
  1073  					Image:      "repo/image:tag",
  1074  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
  1075  						NodeSelector:      overriddenNodeSelectors,
  1076  						PriorityClassName: &overriddenPriorityClassName,
  1077  						Tolerations:       overriddenTolerations,
  1078  						Affinity:          overriddenAffinity,
  1079  					},
  1080  				},
  1081  			},
  1082  			expectedTolerations:       overriddenTolerations,
  1083  			expectedAffinity:          overriddenAffinity,
  1084  			expectedPriorityClassName: overriddenPriorityClassName,
  1085  			expectedNodeSelectors:     overriddenNodeSelectors,
  1086  		}, {
  1087  			title: "priorityClassName annotation takes precedence",
  1088  			catalogSource: &v1alpha1.CatalogSource{
  1089  				ObjectMeta: metav1.ObjectMeta{
  1090  					Name:      "test",
  1091  					Namespace: "testns",
  1092  				},
  1093  				Spec: v1alpha1.CatalogSourceSpec{
  1094  					SourceType: v1alpha1.SourceTypeGrpc,
  1095  					Image:      "repo/image:tag",
  1096  					GrpcPodConfig: &v1alpha1.GrpcPodConfig{
  1097  						PriorityClassName: &overriddenPriorityClassName,
  1098  					},
  1099  				},
  1100  			},
  1101  			expectedTolerations: nil,
  1102  			expectedAffinity:    nil,
  1103  			annotations: map[string]string{
  1104  				CatalogPriorityClassKey: "some-OTHER-prio-class",
  1105  			},
  1106  			expectedPriorityClassName: "some-OTHER-prio-class",
  1107  			expectedNodeSelectors:     defaultNodeSelectors,
  1108  		},
  1109  	}
  1110  
  1111  	for _, testCase := range testCases {
  1112  		pod, err := Pod(testCase.catalogSource, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, testCase.annotations, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
  1113  		require.NoError(t, err)
  1114  		require.Equal(t, testCase.expectedNodeSelectors, pod.Spec.NodeSelector)
  1115  		require.Equal(t, testCase.expectedPriorityClassName, pod.Spec.PriorityClassName)
  1116  		require.Equal(t, testCase.expectedTolerations, pod.Spec.Tolerations)
  1117  		require.Equal(t, testCase.expectedAffinity, pod.Spec.Affinity)
  1118  	}
  1119  }
  1120  
  1121  // baseClusterState returns a list of runtime objects that are required for the tests to run including the
  1122  // target namespace with the assumed default configuration
  1123  func baseClusterState() []runtime.Object {
  1124  	return []runtime.Object{
  1125  		defaultNamespace(),
  1126  	}
  1127  }
  1128  
  1129  // defaultNamespace returns a kubernetes namespace with the assumes default settings,
  1130  // e.g. Pod Security Admission security policy label
  1131  func defaultNamespace() *corev1.Namespace {
  1132  	return &corev1.Namespace{
  1133  		ObjectMeta: metav1.ObjectMeta{
  1134  			Name: testNamespace,
  1135  			Labels: map[string]string{
  1136  				// catalogsource pod security configuration depends on the defaultNamespace psa configuration
  1137  				// adding restricted PSA label as this is the default
  1138  				"pod-security.kubernetes.io/enforce": "restricted",
  1139  			},
  1140  		},
  1141  	}
  1142  }