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
10 changes: 0 additions & 10 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -324,16 +324,6 @@ tasks:
"readinessProbe": null,
"livenessProbe": null,
"command": null
},
{
"name": "proxy",
"readinessProbe": null,
"livenessProbe": null
},
{
"name": "kube-rbac-proxy",
"readinessProbe": null,
"livenessProbe": null
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion build/components/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ firmware:
libvirt: v10.9.0
edk2: stable202411
core:
3p-kubevirt: v1.6.2-v12n.43
3p-kubevirt: v1.6.2-v12n.44
3p-containerized-data-importer: v1.60.3-v12n.19
distribution: 2.8.3
package:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,9 +717,7 @@ func deletePersistentVolumeClaim(ctx context.Context, pvc *corev1.PersistentVolu
var shouldPatch bool
for _, finalizer := range pvc.Finalizers {
switch finalizer {
// When pod completed, we cannot remove pvc, because Kubernetes protects pvc until pod is removed.
// https://github.com/kubernetes/kubernetes/issues/120756
case v1alpha2.FinalizerVDProtection, "kubernetes.io/pvc-protection": // remove
case v1alpha2.FinalizerVDProtection: // remove
shouldPatch = true
default:
newFinalizers = append(newFinalizers, finalizer)
Expand Down
1 change: 1 addition & 0 deletions test/e2e/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ tasks:
- copy
- kubectl
- d8
- precheck:prepare
cmds:
- |
go tool ginkgo -v \
Expand Down
64 changes: 50 additions & 14 deletions test/e2e/internal/config/storageclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ package config
import (
"context"
"fmt"
"os"
"sort"

storagev1 "k8s.io/api/storage/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const NFS = "nfs.csi.k8s.io"
const (
NFS = "nfs.csi.k8s.io"

// StorageClassNameEnv overrides TemplateStorageClass for tests (see README).
StorageClassNameEnv = "STORAGE_CLASS_NAME"
)

// FindDefaultStorageClass returns the default StorageClass from the list.
// It selects the most recently created default StorageClass (by creationTimestamp).
Expand Down Expand Up @@ -85,25 +91,55 @@ func FindImmediateStorageClass(defaultSC *storagev1.StorageClass, scList *storag
return nil
}

// SetImmediateStorageClass finds and sets ImmediateStorageClass in Config.
// It searches for a StorageClass with VolumeBindingMode=Immediate and same provisioner as default StorageClass.
// If default StorageClass already has Immediate binding mode, it will be used.
func (c *Config) SetImmediateStorageClass(ctx context.Context, k8sClient client.Client) error {
if c.StorageClass.DefaultStorageClass == nil {
return fmt.Errorf("default StorageClass is not set")
}

// SetStorageClasses discovers cluster StorageClasses and populates Config.StorageClass fields.
// TemplateStorageClass is taken from StorageClassNameEnv when set, otherwise DefaultStorageClass is used.
func (c *Config) SetStorageClasses(ctx context.Context, k8sClient client.Client) error {
var scList storagev1.StorageClassList
if err := k8sClient.List(ctx, &scList); err != nil {
return fmt.Errorf("failed to list StorageClasses: %w", err)
}

immediateSC := FindImmediateStorageClass(c.StorageClass.DefaultStorageClass, &scList)
if immediateSC == nil {
return fmt.Errorf("immediate StorageClass not found for provisioner %q",
c.StorageClass.DefaultStorageClass.Provisioner)
c.StorageClass.DefaultStorageClass = FindDefaultStorageClass(&scList)
if c.StorageClass.DefaultStorageClass == nil {
return fmt.Errorf("default StorageClass not found in the cluster")
}

c.StorageClass.ImmediateStorageClass = FindImmediateStorageClass(c.StorageClass.DefaultStorageClass, &scList)

templateSC, err := findStorageClassFromEnv(ctx, k8sClient, StorageClassNameEnv, &scList)
if err != nil {
return err
}
if templateSC != nil {
c.StorageClass.TemplateStorageClass = templateSC
} else {
c.StorageClass.TemplateStorageClass = c.StorageClass.DefaultStorageClass
}

c.StorageClass.ImmediateStorageClass = immediateSC
return nil
}

func findStorageClassFromEnv(
ctx context.Context,
k8sClient client.Client,
envName string,
scList *storagev1.StorageClassList,
) (*storagev1.StorageClass, error) {
scName, ok := os.LookupEnv(envName)
if !ok {
return nil, nil
}

for i := range scList.Items {
if scList.Items[i].Name == scName {
return &scList.Items[i], nil
}
}

sc := &storagev1.StorageClass{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: scName}, sc); err != nil {
return nil, fmt.Errorf("failed to get StorageClass %q from %s env: %w", scName, envName, err)
}

return sc, nil
}
7 changes: 6 additions & 1 deletion test/e2e/internal/framework/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package framework

import (
"sync"

apiruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
Expand All @@ -39,9 +41,12 @@ import (

var clients = Clients{}

var clientsOnce sync.Once

func GetClients() Clients {
onceLoadConfig()
InitClients()
initStorageClasses()
return clients
}

Expand Down Expand Up @@ -93,7 +98,7 @@ func (c Clients) Git() gt.Git {
// This should be called before using framework clients.
func InitClients() {
clientsOnce.Do(func() {
_ = GetConfig()
onceLoadConfig()

restConfig, err := conf.ClusterTransport.RestConfig()
if err != nil {
Expand Down
38 changes: 32 additions & 6 deletions test/e2e/internal/framework/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ limitations under the License.
package framework

import (
"context"
"sync"

"github.com/deckhouse/virtualization/test/e2e/internal/config"
)

var (
conf *config.Config
once sync.Once
clientsOnce sync.Once
conf *config.Config
confMu sync.RWMutex
once sync.Once
storageClassesOnce sync.Once
)

func onceLoadConfig() {
Expand All @@ -34,20 +36,44 @@ func onceLoadConfig() {
if err != nil {
panic(err)
}
SetConfig(c)
setConfig(c)
})
}

func initStorageClasses() {
storageClassesOnce.Do(func() {
onceLoadConfig()
InitClients()

confMu.Lock()
defer confMu.Unlock()

if err := conf.SetStorageClasses(context.Background(), clients.client); err != nil {
panic(err)
}
})
}

func GetConfig() *config.Config {
onceLoadConfig()
initStorageClasses()

confMu.RLock()
copied := *conf
confMu.RUnlock()

return &copied
}

// SetConfig sets the config.
// this needs because we have some legacy, config mutating in the main test suite
// should be refactored in the future
//
// Deprecated: config is populated by framework initialization; legacy should not mutate it.
func SetConfig(c *config.Config) {
setConfig(c)
}

func setConfig(c *config.Config) {
confMu.Lock()
conf = c
confMu.Unlock()
}
33 changes: 6 additions & 27 deletions test/e2e/legacy/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
storagev1 "k8s.io/api/storage/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -48,7 +47,6 @@ const (
PhaseReady = "Ready"
PhasePending = "Pending"
PhaseRunning = "Running"
storageClassName = "STORAGE_CLASS_NAME"
testDataDir = "/tmp/testdata"
)

Expand All @@ -67,35 +65,16 @@ func Init() error {

func configure() (err error) {
conf = framework.GetConfig()
defer framework.SetConfig(conf)

clients := framework.GetClients()
kubectl = clients.Kubectl()
kubectl = framework.GetClients().Kubectl()

var scList storagev1.StorageClassList
if err := clients.GenericClient().List(context.Background(), &scList); err != nil {
return fmt.Errorf("failed to list StorageClasses: %w", err)
if conf.StorageClass.TemplateStorageClass == nil {
return fmt.Errorf("TemplateStorageClass is not set")
}

conf.StorageClass.DefaultStorageClass = config.FindDefaultStorageClass(&scList)
if conf.StorageClass.DefaultStorageClass == nil {
return fmt.Errorf("default StorageClass not found in the cluster")
}

conf.StorageClass.ImmediateStorageClass = config.FindImmediateStorageClass(conf.StorageClass.DefaultStorageClass, &scList)

scFromEnv, err := GetStorageClassFromEnv(storageClassName)
if err != nil {
return err
}

if scFromEnv != nil {
conf.StorageClass.TemplateStorageClass = scFromEnv
} else {
conf.StorageClass.TemplateStorageClass = conf.StorageClass.DefaultStorageClass
}

if err = SetStorageClass(testDataDir, map[string]string{storageClassName: conf.StorageClass.TemplateStorageClass.Name}); err != nil {
if err = SetStorageClass(testDataDir, map[string]string{
config.StorageClassNameEnv: conf.StorageClass.TemplateStorageClass.Name,
}); err != nil {
return err
}

Expand Down
14 changes: 0 additions & 14 deletions test/e2e/legacy/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,20 +245,6 @@ func WaitResources(resources []string, resource kc.Resource, opts kc.WaitOptions
Expect(waitErr).To(BeEmpty(), "should observe resources in '%s' state before %s timeout", opts.For, opts.Timeout.String())
}

func GetStorageClassFromEnv(envName string) (*storagev1.StorageClass, error) {
sc := &storagev1.StorageClass{}
scName, ok := os.LookupEnv(envName)
if ok {
err := GetObject(kc.ResourceStorageClass, scName, sc, kc.GetOptions{})
if err != nil {
return nil, err
}
return sc, nil
}

return nil, nil
}

func SetStorageClass(tmplRoot string, storageClasse map[string]string) error {
return filepath.Walk(tmplRoot, func(path string, info os.FileInfo, err error) error {
if err != nil {
Expand Down
Loading