@@ -3,6 +3,7 @@ package controllers_test
33import (
44 "context"
55 "fmt"
6+ "slices"
67 "testing"
78 "time"
89
@@ -272,10 +273,125 @@ func AssertPVCHasSize(t *testing.T, pvc *corev1.PersistentVolumeClaim, expectedS
272273 "PVC should request %s storage, got %s" , expectedSize , storageRequest .String ())
273274}
274275
275- func ReconcileDistribution (t * testing.T , instance * llamav1alpha1.LlamaStackDistribution ) {
276+ // AssertServicePortMatches verifies that a service has the expected port configuration.
277+ func AssertServicePortMatches (t * testing.T , service * corev1.Service , expectedPort corev1.ServicePort ) {
278+ t .Helper ()
279+ require .Len (t , service .Spec .Ports , 1 , "Service should have exactly one port" )
280+ require .Equal (t , expectedPort , service .Spec .Ports [0 ], "Service port should match expected" )
281+ }
282+
283+ // AssertServiceAndDeploymentPortsAlign verifies that service target port matches deployment container port.
284+ func AssertServiceAndDeploymentPortsAlign (t * testing.T , service * corev1.Service , deployment * appsv1.Deployment ) {
285+ t .Helper ()
286+ require .Len (t , service .Spec .Ports , 1 , "Service should have exactly one port" )
287+ require .Len (t , deployment .Spec .Template .Spec .Containers , 1 , "Deployment should have exactly one container" )
288+ require .Len (t , deployment .Spec .Template .Spec .Containers [0 ].Ports , 1 , "Container should have exactly one port" )
289+
290+ serviceTargetPort := service .Spec .Ports [0 ].TargetPort .IntVal
291+ containerPort := deployment .Spec .Template .Spec .Containers [0 ].Ports [0 ].ContainerPort
292+ require .Equal (t , serviceTargetPort , containerPort , "Service target port should match deployment container port" )
293+ }
294+
295+ // AssertServiceSelectorMatches verifies that a service has the expected selector.
296+ func AssertServiceSelectorMatches (t * testing.T , service * corev1.Service , expectedSelector map [string ]string ) {
297+ t .Helper ()
298+ require .Equal (t , expectedSelector , service .Spec .Selector , "Service selector should match expected" )
299+ }
300+
301+ // AssertServiceAndDeploymentSelectorsAlign verifies that service selector matches deployment pod labels.
302+ func AssertServiceAndDeploymentSelectorsAlign (t * testing.T , service * corev1.Service , deployment * appsv1.Deployment ) {
303+ t .Helper ()
304+ require .Equal (t , service .Spec .Selector , deployment .Spec .Template .Labels , "Service selector should match deployment pod labels" )
305+ }
306+
307+ // AssertNetworkPolicyTargetsDeploymentPods verifies that network policy targets the same pods as deployment.
308+ func AssertNetworkPolicyTargetsDeploymentPods (t * testing.T , networkPolicy * networkingv1.NetworkPolicy , deployment * appsv1.Deployment ) {
309+ t .Helper ()
310+ require .Equal (t , deployment .Spec .Template .Labels , networkPolicy .Spec .PodSelector .MatchLabels ,
311+ "NetworkPolicy should target same pods as deployment" )
312+ }
313+
314+ // hasMatchingIngressRule is a generic helper function that checks if a network policy
315+ // contains at least one ingress rule that meets two specific criteria:
316+ // 1. The rule allows traffic on the specified 'port'.
317+ // 2. The rule's source (the 'From' field) matches a custom condition defined by the 'peerPredicate'.
318+ func hasMatchingIngressRule (
319+ t * testing.T ,
320+ policy * networkingv1.NetworkPolicy ,
321+ port int32 ,
322+ peerPredicate func (peer networkingv1.NetworkPolicyPeer ) bool ,
323+ ) bool {
324+ t .Helper ()
325+ for _ , rule := range policy .Spec .Ingress {
326+ // First, check if this rule's source (any of its 'From' peers) matches our criteria.
327+ // If not, move on to the next one.
328+ if ! slices .ContainsFunc (rule .From , peerPredicate ) {
329+ continue
330+ }
331+
332+ // Check if this same rule also allows traffic on the required port.
333+ // Both conditions must be met by a single rule for the policy to be
334+ // considered valid.
335+ portMatches := slices .ContainsFunc (rule .Ports , func (p networkingv1.NetworkPolicyPort ) bool {
336+ return p .Port != nil && p .Port .IntVal == port
337+ })
338+
339+ if portMatches {
340+ // This rule meets both the source and port requirements.
341+ return true
342+ }
343+ }
344+
345+ // Returning false signifies that no single rule in the entire policy satisfied
346+ // both the source (predicate) and port conditions for this specific check.
347+ return false
348+ }
349+
350+ // AssertNetworkPolicyAllowsDeploymentPort verifies that the network policy
351+ // allows traffic from both intra-stack components and the operator.
352+ func AssertNetworkPolicyAllowsDeploymentPort (t * testing.T , networkPolicy * networkingv1.NetworkPolicy , deployment * appsv1.Deployment , operatorNamespace string ) {
353+ t .Helper ()
354+ require .Len (t , deployment .Spec .Template .Spec .Containers , 1 , "Deployment should have exactly one container" )
355+ require .Len (t , deployment .Spec .Template .Spec .Containers [0 ].Ports , 1 , "Container should have exactly one port" )
356+ containerPort := deployment .Spec .Template .Spec .Containers [0 ].Ports [0 ].ContainerPort
357+
358+ // Behavior 1: Verify a rule exists for intra-stack communication.
359+ intraStackPredicate := func (peer networkingv1.NetworkPolicyPeer ) bool {
360+ return peer .PodSelector != nil && peer .PodSelector .MatchLabels ["app.kubernetes.io/part-of" ] == "llama-stack"
361+ }
362+ require .True (t ,
363+ hasMatchingIngressRule (t , networkPolicy , containerPort , intraStackPredicate ),
364+ "NetworkPolicy is missing a rule to allow traffic from other Llama Stack components on port %d" , containerPort )
365+
366+ // Behavior 2: Verify a rule for operator communication exists.
367+ // This allows the operator to communicate with the server pods it manages
368+ // from its separate namespace for tasks like health checks.
369+ operatorPredicate := func (peer networkingv1.NetworkPolicyPeer ) bool {
370+ return peer .NamespaceSelector != nil && peer .NamespaceSelector .MatchLabels ["kubernetes.io/metadata.name" ] == operatorNamespace
371+ }
372+ require .True (t ,
373+ hasMatchingIngressRule (t , networkPolicy , containerPort , operatorPredicate ),
374+ "NetworkPolicy is missing a rule to allow traffic from the operator in namespace '%s' on port %d" , operatorNamespace , containerPort )
375+ }
376+
377+ // AssertNetworkPolicyIsIngressOnly verifies that network policy is configured for ingress-only traffic.
378+ func AssertNetworkPolicyIsIngressOnly (t * testing.T , networkPolicy * networkingv1.NetworkPolicy ) {
379+ t .Helper ()
380+ expectedPolicyTypes := []networkingv1.PolicyType {networkingv1 .PolicyTypeIngress }
381+ require .Equal (t , expectedPolicyTypes , networkPolicy .Spec .PolicyTypes , "NetworkPolicy should be ingress-only" )
382+ }
383+
384+ func AssertServiceAccountDeploymentAlign (t * testing.T , deployment * appsv1.Deployment , serviceAccount * corev1.ServiceAccount ) {
385+ t .Helper ()
386+ require .Equal (t , serviceAccount .Name , deployment .Spec .Template .Spec .ServiceAccountName ,
387+ "Deployment should use the created ServiceAccount for pod permissions" )
388+ }
389+
390+ func ReconcileDistribution (t * testing.T , instance * llamav1alpha1.LlamaStackDistribution , enableNetworkPolicy bool ) {
276391 t .Helper ()
277392 // Create reconciler and run reconciliation
278393 reconciler := createTestReconciler ()
394+ reconciler .EnableNetworkPolicy = enableNetworkPolicy
279395 _ , err := reconciler .Reconcile (context .Background (), ctrl.Request {
280396 NamespacedName : types.NamespacedName {
281397 Name : instance .Name ,
0 commit comments