• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / containerized-data-importer / #5676

17 Nov 2025 10:06PM UTC coverage: 58.665% (-0.08%) from 58.748%
#5676

push

travis-ci

web-flow
Copy Events from tmp PVCs during Clone (#3933)

* move CopyEvents to common package so it can be called from other controllers

Signed-off-by: dsanatar <dsanatar@redhat.com>

* copy events from tmp clone pvcs to their target pvc

Signed-off-by: dsanatar <dsanatar@redhat.com>

---------

Signed-off-by: dsanatar <dsanatar@redhat.com>

19 of 64 new or added lines in 6 files covered. (29.69%)

7 existing lines in 1 file now uncovered.

17389 of 29641 relevant lines covered (58.67%)

0.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.91
/pkg/controller/clone/snap-clone.go
1
package clone
2

3
import (
4
        "context"
5
        "fmt"
6

7
        "github.com/go-logr/logr"
8
        snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1"
9

10
        corev1 "k8s.io/api/core/v1"
11
        "k8s.io/client-go/tools/record"
12
        "k8s.io/utils/ptr"
13

14
        "sigs.k8s.io/controller-runtime/pkg/client"
15
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
16

17
        cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
18
        cc "kubevirt.io/containerized-data-importer/pkg/controller/common"
19
)
20

21
// SnapshotClonePhaseName is the name of the snapshot clone phase
22
const SnapshotClonePhaseName = "SnapshotClone"
23

24
// SnapshotClonePhase waits for a snapshot to be ready and creates a PVC from it
25
type SnapshotClonePhase struct {
26
        Owner          client.Object
27
        Namespace      string
28
        SourceName     string
29
        DesiredClaim   *corev1.PersistentVolumeClaim
30
        OwnershipLabel string
31
        Client         client.Client
32
        Log            logr.Logger
33
        Recorder       record.EventRecorder
34
}
35

36
var _ Phase = &SnapshotClonePhase{}
37

38
// Name returns the name of the phase
39
func (p *SnapshotClonePhase) Name() string {
×
40
        return SnapshotClonePhaseName
×
41
}
×
42

43
// Reconcile ensures a snapshot is created correctly
44
func (p *SnapshotClonePhase) Reconcile(ctx context.Context) (*reconcile.Result, error) {
1✔
45
        pvc := &corev1.PersistentVolumeClaim{}
1✔
46
        exists, err := getResource(ctx, p.Client, p.Namespace, p.DesiredClaim.Name, pvc)
1✔
47
        if err != nil {
1✔
48
                return nil, err
×
49
        }
×
50

51
        if !exists {
2✔
52
                snapshot := &snapshotv1.VolumeSnapshot{}
1✔
53
                exists, err := getResource(ctx, p.Client, p.Namespace, p.SourceName, snapshot)
1✔
54
                if err != nil {
1✔
55
                        return nil, err
×
56
                }
×
57

58
                if !exists {
2✔
59
                        return nil, fmt.Errorf("source snapshot does not exist")
1✔
60
                }
1✔
61

62
                if !cc.IsSnapshotReady(snapshot) {
2✔
63
                        return &reconcile.Result{}, nil
1✔
64
                }
1✔
65

66
                pvc, err = p.createClaim(ctx, snapshot)
1✔
67
                if err != nil {
1✔
68
                        return nil, err
×
69
                }
×
70
        }
71

72
        targetPvc, err := cc.GetAnnotatedEventSource(ctx, p.Client, pvc)
1✔
73
        if err != nil {
1✔
NEW
74
                return nil, err
×
NEW
75
        }
×
76
        cc.CopyEvents(pvc, targetPvc, p.Client, p.Recorder)
1✔
77

1✔
78
        done, err := isClaimBoundOrWFFC(ctx, p.Client, pvc)
1✔
79
        if err != nil {
1✔
80
                return nil, err
×
81
        }
×
82

83
        if !done {
2✔
84
                return &reconcile.Result{}, nil
1✔
85
        }
1✔
86

87
        return nil, nil
1✔
88
}
89

90
func (p *SnapshotClonePhase) createClaim(ctx context.Context, snapshot *snapshotv1.VolumeSnapshot) (*corev1.PersistentVolumeClaim, error) {
1✔
91
        claim := p.DesiredClaim.DeepCopy()
1✔
92
        claim.Namespace = p.Namespace
1✔
93
        claim.Spec.DataSourceRef = &corev1.TypedObjectReference{
1✔
94
                APIGroup: ptr.To[string]("snapshot.storage.k8s.io"),
1✔
95
                Kind:     "VolumeSnapshot",
1✔
96
                Name:     p.SourceName,
1✔
97
        }
1✔
98

1✔
99
        if snapshot.Status == nil || snapshot.Status.RestoreSize == nil {
1✔
100
                return nil, fmt.Errorf("snapshot missing restoresize")
×
101
        }
×
102

103
        // 0 restore size is a special case, provisioners that do that seem to allow restoring to bigger pvcs
104
        rs := snapshot.Status.RestoreSize
1✔
105
        if !rs.IsZero() {
2✔
106
                p.Log.V(3).Info("setting desired pvc request size to", "restoreSize", *rs)
1✔
107
                claim.Spec.Resources.Requests[corev1.ResourceStorage] = *rs
1✔
108
        }
1✔
109

110
        cc.AddAnnotation(claim, cc.AnnEventSourceKind, p.Owner.GetObjectKind().GroupVersionKind().Kind)
1✔
111
        cc.AddAnnotation(claim, cc.AnnEventSource, fmt.Sprintf("%s/%s", p.Owner.GetNamespace(), p.Owner.GetName()))
1✔
112
        cc.AddAnnotation(claim, cc.AnnPopulatorKind, cdiv1.VolumeCloneSourceRef)
1✔
113
        if p.OwnershipLabel != "" {
2✔
114
                AddOwnershipLabel(p.OwnershipLabel, claim, p.Owner)
1✔
115
        }
1✔
116
        cc.AddLabel(claim, cc.LabelExcludeFromVeleroBackup, "true")
1✔
117

1✔
118
        if err := p.Client.Create(ctx, claim); err != nil {
1✔
119
                checkQuotaExceeded(p.Recorder, p.Owner, err)
×
120
                return nil, err
×
121
        }
×
122

123
        return claim, nil
1✔
124
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc