Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ require (
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235
github.com/openshift/library-go v0.0.0-20251015151611-6fc7a74b67c5
github.com/operator-framework/api v0.36.0
github.com/ovn-org/ovn-kubernetes/go-controller v0.0.0-20250118001652-a8b9c3c31417
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -892,8 +892,6 @@ github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20251001123353-fd5b1fb35db1 h1:PMTg
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20251001123353-fd5b1fb35db1/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/operator-framework/api v0.36.0 h1:6+duRhamCvB540JbvNp/1+Pot7luff7HqdAOm9bAntg=
github.com/operator-framework/api v0.36.0/go.mod h1:QSmHMx8XpGsNWvjU5CUelVZC916VLp/TZhfYvGKpghM=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/ovn-org/ovn-kubernetes/go-controller v0.0.0-20250118001652-a8b9c3c31417 h1:7k+dokKFfpICbkpX5TvvpFbKTFsl/6YQd46EpY2JNhc=
github.com/ovn-org/ovn-kubernetes/go-controller v0.0.0-20250118001652-a8b9c3c31417/go.mod h1:9LxDV3rAHlGHAYtVrT62y/fqfIxc5RrDiYi9RVeD0gg=
Expand Down
174 changes: 2 additions & 172 deletions test/extended/storage/storage_networkpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ import (
"fmt"
"strings"

"github.com/blang/semver/v4"
g "github.com/onsi/ginkgo/v2"
o "github.com/onsi/gomega"
exutil "github.com/openshift/origin/test/extended/util"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
e2e "k8s.io/kubernetes/test/e2e/framework"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// storage_networkpolicy.go contains tests for verifying network policy configurations
Expand All @@ -28,14 +25,8 @@ import (
// 2. CSI driver resources - verifies network policy labels on platform-specific CSI
// drivers (AWS EBS/EFS, Azure Disk/File, GCP PD/Filestore, vSphere, IBM Cloud,
// OpenStack Cinder/Manila, SMB)
// 3. LSO (Local Storage Operator) resources - verifies network policy labels on
// related deployment and diskmaker daemonsets
// 4. NetworkPolicy resources - ensures required NetworkPolicies exist with correct
// PodSelector labels for CSO, CSI, and LSO namespaces
//
// LSO-specific Design Considerations:
// - LSONamespace is defined as a variable (not constant) because LSO can be installed
// in a user-specified namespace, allowing for customization based on actual deployment
// 3. NetworkPolicy resources - ensures required NetworkPolicies exist with correct
// PodSelector labels for CSO, CSI

// ResourceType defines the type of Openshift workload resource
type ResourceType string
Expand All @@ -45,13 +36,6 @@ const (
ResourceTypeDaemonSet ResourceType = "DaemonSet"
)

// lsoInfo contains information about the Local Storage Operator installation
type lsoInfo struct {
Installed bool
Namespace string
Version string
}

// resourceCheck defines a check for a workload resource (Deployment, DaemonSet, etc.)
type resourceCheck struct {
ResourceType ResourceType
Expand All @@ -68,11 +52,6 @@ var (
npLabelOperatorMetricsRange = map[string]string{"openshift.storage.network-policy.operator-metrics-range": "allow"}
npLabelMetricsRange = map[string]string{"openshift.storage.network-policy.metrics-range": "allow"}
npLabelAllEgress = map[string]string{"openshift.storage.network-policy.all-egress": "allow"}
// LSO specific network policy labels
npLabelLSOAPIServer = map[string]string{"openshift.storage.network-policy.lso.api-server": "allow"}
npLabelLSODNS = map[string]string{"openshift.storage.network-policy.lso.dns": "allow"}
npLabelLSOOperatorMetrics = map[string]string{"openshift.storage.network-policy.lso.operator-metrics": "allow"}
npLabelLSODiskmakerMetrics = map[string]string{"openshift.storage.network-policy.lso.diskmaker-metrics": "allow"}
)

func mergeLabels(maps ...map[string]string) map[string]string {
Expand All @@ -94,9 +73,6 @@ var (
csiOperatorWithAllEgressRequiredLabels = mergeLabels(npLabelAPI, npLabelDNS, npLabelOperatorMetricsRange, npLabelAllEgress)
csiControllerRequiredLabels = mergeLabels(npLabelAPI, npLabelDNS, npLabelMetricsRange)
csiControllerWithAllEgressRequiredLabels = mergeLabels(npLabelAPI, npLabelDNS, npLabelMetricsRange, npLabelAllEgress)
// LSO specific required labels
lsoOperatorRequiredLabels = mergeLabels(npLabelLSOAPIServer, npLabelLSODNS, npLabelLSOOperatorMetrics)
lsoDiskmakerRequiredLabels = mergeLabels(npLabelLSOAPIServer, npLabelLSODNS, npLabelLSODiskmakerMetrics)
)

type npCheck struct {
Expand Down Expand Up @@ -140,26 +116,11 @@ var networkPolicyChecks = []npCheck{
// },
}

// getLSONetworkPolicyCheck returns the LSO network policy check configuration
// based on the detected LSO installation information
func getLSONetworkPolicyCheck(lso *lsoInfo) npCheck {
return npCheck{
Namespace: lso.Namespace,
RequiredPodSelectors: []map[string]string{
npLabelLSOAPIServer,
npLabelLSODNS,
npLabelLSOOperatorMetrics,
npLabelLSODiskmakerMetrics,
},
}
}

var _ = g.Describe("[sig-storage][OCPFeature:StorageNetworkPolicy] Storage Network Policy", func() {
defer g.GinkgoRecover()
var (
oc = exutil.NewCLI("storage-network-policy")
currentPlatform = e2e.TestContext.Provider
lsoInstallInfo *lsoInfo // LSO installation information detected once per suite
)

g.BeforeEach(func() {
Expand All @@ -168,20 +129,6 @@ var _ = g.Describe("[sig-storage][OCPFeature:StorageNetworkPolicy] Storage Netwo
if isMicroShift {
g.Skip("Storage Network Policy tests are not supported on MicroShift")
}

// Detect LSO installation only once (cache the result)
if lsoInstallInfo == nil {
lsoInstallInfo, err = getLSOInfo(oc)
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to detect LSO installation")

if lsoInstallInfo.Installed {
supported := isLSOVersionSupported(lsoInstallInfo.Version)
g.By(fmt.Sprintf("Detected LSO installed in namespace: %s, version: %s (network policy support: %v)",
lsoInstallInfo.Namespace, lsoInstallInfo.Version, supported))
} else {
g.By("LSO is not installed on this cluster")
}
}
})

g.It("should verify required labels for CSO related Operators", func() {
Expand Down Expand Up @@ -364,59 +311,6 @@ var _ = g.Describe("[sig-storage][OCPFeature:StorageNetworkPolicy] Storage Netwo
runResourceChecks(oc, CSIResourcesToCheck, currentPlatform)
})

g.It("should verify required labels for LSO related resources", func() {
// Skip if LSO is not installed or version is lower than 4.21.0
if !lsoInstallInfo.Installed {
g.Skip("LSO is not installed on this cluster")
}

if !isLSOVersionSupported(lsoInstallInfo.Version) {
g.Skip(fmt.Sprintf("LSO network policy support requires version >= 4.21.0, current version: %s", lsoInstallInfo.Version))
}

LSOResourcesToCheck := []resourceCheck{
{
ResourceType: ResourceTypeDeployment,
Namespace: lsoInstallInfo.Namespace,
Name: "local-storage-operator",
Platform: "all",
RequiredLabels: lsoOperatorRequiredLabels,
},
{
ResourceType: ResourceTypeDaemonSet,
Namespace: lsoInstallInfo.Namespace,
Name: "diskmaker-manager",
Platform: "all",
RequiredLabels: lsoDiskmakerRequiredLabels,
},
{
ResourceType: ResourceTypeDaemonSet,
Namespace: lsoInstallInfo.Namespace,
Name: "diskmaker-discovery",
Platform: "all",
RequiredLabels: lsoDiskmakerRequiredLabels,
},
}

runResourceChecks(oc, LSOResourcesToCheck, currentPlatform)
})

g.It("should ensure required NetworkPolicies exist with correct labels for LSO", func() {
// Skip if LSO is not installed or version is lower than 4.21.0
if !lsoInstallInfo.Installed {
g.Skip("LSO is not installed on this cluster")
}

if !isLSOVersionSupported(lsoInstallInfo.Version) {
g.Skip(fmt.Sprintf("LSO network policy support requires version >= 4.21.0, current version: %s", lsoInstallInfo.Version))
}

// Get LSO network policy check configuration
lsoCheck := getLSONetworkPolicyCheck(lsoInstallInfo)

verifyNetworkPolicyPodSelectors(oc, lsoCheck.Namespace, lsoCheck.RequiredPodSelectors)
})

g.It("should ensure required NetworkPolicies exist with correct labels", func() {
for _, c := range networkPolicyChecks {
_, err := oc.AdminKubeClient().CoreV1().Namespaces().Get(context.TODO(), c.Namespace, metav1.GetOptions{})
Expand Down Expand Up @@ -496,70 +390,6 @@ func runResourceChecks(oc *exutil.CLI, resources []resourceCheck, currentPlatfor
}
}

// isLSOVersionSupported checks if the LSO version is 4.21.0 or higher
// Supported version formats: "4.21.0", "4.21.0-202511252120"
func isLSOVersionSupported(versionStr string) bool {
// Minimum required version for LSO network policy support
minVersion := semver.MustParse("4.21.0")

// Parse the LSO version
// The version string may contain build metadata (e.g., "4.21.0-202511252120")
// semver.Parse handles this correctly
version, err := semver.Parse(versionStr)
if err != nil {
e2e.Logf("Failed to parse LSO version %q: %v", versionStr, err)
return false
}

// Compare versions: returns true if version >= minVersion
return version.GTE(minVersion)
}

// getLSOInfo detects if LSO is installed by searching for local-storage-operator CSV
// across all namespaces and returns its namespace and version information
func getLSOInfo(oc *exutil.CLI) (*lsoInfo, error) {
info := &lsoInfo{
Installed: false,
}

// Create controller-runtime client
clusterConfig := oc.AdminConfig()
clusterClient, err := client.New(clusterConfig, client.Options{})
if err != nil {
return info, fmt.Errorf("failed to create controller-runtime client: %v", err)
}

// Add operatorsv1alpha1 to scheme
err = operatorsv1alpha1.AddToScheme(clusterClient.Scheme())
if err != nil {
return info, fmt.Errorf("failed to add operators.coreos.com/v1alpha1 to scheme: %v", err)
}

// List all ClusterServiceVersions across all namespaces
csvList := &operatorsv1alpha1.ClusterServiceVersionList{}
err = clusterClient.List(context.TODO(), csvList)
if err != nil {
return info, fmt.Errorf("failed to list ClusterServiceVersions: %v", err)
}

// Search for local-storage-operator CSV
for _, csv := range csvList.Items {
// Match CSV name pattern: local-storage-operator.*
if strings.HasPrefix(csv.Name, "local-storage-operator") {
// Only consider CSVs in Succeeded phase
if csv.Status.Phase == operatorsv1alpha1.CSVPhaseSucceeded {
info.Installed = true
info.Namespace = csv.Namespace
info.Version = csv.Spec.Version.String()
return info, nil
}
}
}

// LSO not found or not in Succeeded phase
return info, nil
}

// podSelectorContainsLabels checks if actualLabels contains all key-value pairs from requiredLabels
func podSelectorContainsLabels(actualLabels map[string]string, requiredLabels map[string]string) bool {
for key, value := range requiredLabels {
Expand Down
Loading