Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ const (
IndexFieldVIByVDSnapshot = "vi,spec.DataSource.ObjectRef.Name,.Kind=VirtualDiskSnapshot"
IndexFieldCVIByVDSnapshot = "cvi,spec.DataSource.ObjectRef.Name,.Kind=VirtualDiskSnapshot"

IndexFieldVDByStorageClass = "vd.spec.PersistentVolumeClaim.StorageClass"
IndexFieldVIByStorageClass = "vi.spec.PersistentVolumeClaim.StorageClass"
IndexFieldVDByStorageClass = "vd.spec.PersistentVolumeClaim.StorageClass"
IndexFieldVIByStorageClass = "vi.spec.PersistentVolumeClaim.StorageClass"
IndexFieldVIByNotReadyStorageClass = "vi,status.conditions[].type,StorageClassReady"

IndexFieldVMSnapshotByVM = "spec.virtualMachineName"
IndexFieldVMSnapshotByVDSnapshot = "status.virtualDiskSnapshotNames"
Expand Down Expand Up @@ -72,6 +73,7 @@ func IndexALL(ctx context.Context, mgr manager.Manager) error {
IndexVDByStorageClass,
IndexVIByVDSnapshot,
IndexVIByStorageClass,
IndexVIByNotReadyStorageClass,
IndexCVIByVDSnapshot,
IndexVMIPByAddress,
IndexVMBDAByVM,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ package indexer
import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
"github.com/deckhouse/virtualization/api/core/v1alpha2/vicondition"
)

func IndexVIByVDSnapshot(ctx context.Context, mgr manager.Manager) error {
Expand Down Expand Up @@ -61,3 +63,20 @@ func IndexVIByStorageClass(ctx context.Context, mgr manager.Manager) error {
}
})
}

func IndexVIByNotReadyStorageClass(ctx context.Context, mgr manager.Manager) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why with this name you indexing by sc ready? And ignore non pvc VI please.

return mgr.GetFieldIndexer().IndexField(ctx, &virtv2.VirtualImage{}, IndexFieldVIByNotReadyStorageClass, func(object client.Object) []string {
vi, ok := object.(*virtv2.VirtualImage)
if !ok || vi == nil {
return nil
}

for _, condition := range vi.Status.Conditions {
if condition.Type == string(vicondition.StorageClassReadyType) && condition.Status == metav1.ConditionTrue {
return []string{condition.Type}
}
}

return nil
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/deckhouse/virtualization-controller/pkg/common/pointer"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
"github.com/deckhouse/virtualization-controller/pkg/controller/kvbuilder"
mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api"
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
"github.com/deckhouse/virtualization-controller/pkg/dvcr"
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
Expand Down Expand Up @@ -608,8 +609,32 @@ func (s DiskService) GetStorageClass(ctx context.Context, storageClassName *stri
}

func (s DiskService) GetDefaultStorageClass(ctx context.Context) (*storev1.StorageClass, error) {
var (
moduleConfigViDefaultStorageClass string
moduleConfig mcapi.ModuleConfig
moduleConfigName = "virtualization"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it change?

)
err := s.client.Get(ctx, types.NamespacedName{Name: moduleConfigName}, &moduleConfig, &client.GetOptions{})
if err != nil {
return nil, err
}

if virtualImages, ok := moduleConfig.Spec.Settings["virtualImages"].(map[string]interface{}); ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not hardcode please, use constant not string literal (set it if needed), next line too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"virtualImages" var seems like slice of VI, use virtualImagesSetting or something

if defaultClass, ok := virtualImages["defaultStorageClassName"].(string); ok {
moduleConfigViDefaultStorageClass = defaultClass
}
}

if moduleConfigViDefaultStorageClass != "" {
moduleConfigViDefaultStorageClassObj, err := s.getStorageClass(ctx, moduleConfigViDefaultStorageClass)
if err != nil {
return nil, err
}
return moduleConfigViDefaultStorageClassObj, nil
}

var scs storev1.StorageClassList
err := s.client.List(ctx, &scs, &client.ListOptions{})
err = s.client.List(ctx, &scs, &client.ListOptions{})
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright 2025 Flant JSC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package watcher

import (
"context"
"fmt"
"log/slog"

"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"

"github.com/deckhouse/virtualization-controller/pkg/controller/indexer"
mcapi "github.com/deckhouse/virtualization-controller/pkg/controller/moduleconfig/api"
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
"github.com/deckhouse/virtualization/api/core/v1alpha2/vicondition"
)

type ModuleConfigWatcher struct {
client client.Client
logger *slog.Logger
}

func NewModuleConfigWatcher(client client.Client) *StorageClassWatcher {
return &StorageClassWatcher{
client: client,
logger: slog.Default().With("watcher", "moduleconfig"),
}
}

func (w ModuleConfigWatcher) Watch(mgr manager.Manager, ctr controller.Controller) error {
return ctr.Watch(
source.Kind(mgr.GetCache(), &mcapi.ModuleConfig{}),
handler.EnqueueRequestsFromMapFunc(w.enqueueRequests),
predicate.Funcs{
CreateFunc: func(event event.CreateEvent) bool { return true },
DeleteFunc: func(event event.DeleteEvent) bool { return true },
UpdateFunc: func(event event.UpdateEvent) bool {
oldMc, oldOk := event.ObjectOld.(*mcapi.ModuleConfig)
newMc, newOk := event.ObjectNew.(*mcapi.ModuleConfig)
if !oldOk || !newOk {
return false
}
var (
oldViDefaultSc string
newViDefaultSc string
)
if virtualImages, ok := oldMc.Spec.Settings["virtualImages"].(map[string]interface{}); ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use consts, not string literals

if defaultClass, ok := virtualImages["defaultStorageClassName"].(string); ok {
oldViDefaultSc = defaultClass
}
}
if virtualImages, ok := newMc.Spec.Settings["virtualImages"].(map[string]interface{}); ok {
if defaultClass, ok := virtualImages["defaultStorageClassName"].(string); ok {
oldViDefaultSc = defaultClass
}
}
return oldViDefaultSc != newViDefaultSc
},
},
)
}

func (w ModuleConfigWatcher) enqueueRequests(ctx context.Context, object client.Object) []reconcile.Request {
var vis virtv2.VirtualImageList
err := w.client.List(ctx, &vis, &client.ListOptions{
FieldSelector: fields.OneTermEqualSelector(indexer.IndexFieldVIByNotReadyStorageClass, string(vicondition.StorageClassReadyType)),
})
if err != nil {
w.logger.Error(fmt.Sprintf("failed to list virtual images: %s", err))
return []reconcile.Request{}
}

var requests []reconcile.Request
for _, vi := range vis.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: vi.Name,
Namespace: vi.Namespace,
},
})
}

return requests
}
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ func (r *Reconciler) SetupController(_ context.Context, mgr manager.Manager, ctr
watcher.NewStorageClassWatcher(mgr.GetClient()),
watcher.NewVirtualMachineWatcher(mgr.GetClient()),
watcher.NewVirtualDiskSnapshotWatcher(mgr.GetClient()),
watcher.NewModuleConfigWatcher(mgr.GetClient()),
} {
err := w.Watch(mgr, ctr)
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions templates/virtualization-controller/rbac-for-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ rules:
verbs:
- patch
- update
- apiGroups:
- deckhouse.io
resources:
- moduleconfigs
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
Loading