containerized-data-importer/pkg/controller/clone/host-clone.go
Michael Henriksen f88fab69dc
PVC Clone Populator (#2709)
* touch up zero restoresize snapshot

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* clone populator

only supports PVC source now

snapshot coming soon

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* more unit tests

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* unit test for clone populator

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* func tests for clone populator

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* move clone populator cleanup function to planner

other review comments

verifier pod should bount readonly

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* add readonly flag to test executor pods

synchronize get hash calls

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* increase linter timeout

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* better/explicit readonly support for test pods

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* check pv for driver info before looking up storageclass as it may not exist

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* addressed review comments

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* chooseStrategy shoud generate more events

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

---------

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
2023-05-24 05:11:52 +02:00

132 lines
3.4 KiB
Go

package clone
import (
"context"
"fmt"
"net/http"
"time"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
cc "kubevirt.io/containerized-data-importer/pkg/controller/common"
)
// HostClonePhase creates and monitors a dumb clone operation
type HostClonePhase struct {
Owner client.Object
Namespace string
SourceName string
DesiredClaim *corev1.PersistentVolumeClaim
ImmediateBind bool
OwnershipLabel string
Preallocation bool
PriorityClassName string
Client client.Client
Log logr.Logger
Recorder record.EventRecorder
}
var _ Phase = &HostClonePhase{}
var _ ProgressReporter = &HostClonePhase{}
var httpClient *http.Client
func init() {
httpClient = cc.BuildHTTPClient(httpClient)
}
// Name returns the name of the phase
func (p *HostClonePhase) Name() string {
return "HostClone"
}
// Progress returns the progress of the operation as a percentage
func (p *HostClonePhase) Progress(ctx context.Context) (string, error) {
pvc := &corev1.PersistentVolumeClaim{}
exists, err := getResource(ctx, p.Client, p.Namespace, p.DesiredClaim.Name, pvc)
if err != nil {
return "", err
}
podName := pvc.Annotations[cc.AnnCloneSourcePod]
if !exists || podName == "" {
return "", nil
}
args := &cc.ProgressFromClaimArgs{
Client: p.Client,
HTTPClient: httpClient,
Claim: pvc,
PodNamespace: p.Namespace,
PodName: podName,
OwnerUID: string(p.Owner.GetUID()),
}
progress, err := cc.ProgressFromClaim(ctx, args)
if err != nil {
return "", err
}
return progress, nil
}
// Reconcile creates the desired pvc and waits for the operation to complete
func (p *HostClonePhase) Reconcile(ctx context.Context) (*reconcile.Result, error) {
actualClaim := &corev1.PersistentVolumeClaim{}
exists, err := getResource(ctx, p.Client, p.Namespace, p.DesiredClaim.Name, actualClaim)
if err != nil {
return nil, err
}
if !exists {
actualClaim, err = p.createClaim(ctx)
if err != nil {
return nil, err
}
}
if !hostCloneComplete(actualClaim) {
// requeue to update status
return &reconcile.Result{RequeueAfter: 3 * time.Second}, nil
}
return nil, nil
}
func (p *HostClonePhase) createClaim(ctx context.Context) (*corev1.PersistentVolumeClaim, error) {
claim := p.DesiredClaim.DeepCopy()
claim.Namespace = p.Namespace
cc.AddAnnotation(claim, cc.AnnPreallocationRequested, fmt.Sprintf("%t", p.Preallocation))
cc.AddAnnotation(claim, cc.AnnOwnerUID, string(p.Owner.GetUID()))
cc.AddAnnotation(claim, cc.AnnPodRestarts, "0")
cc.AddAnnotation(claim, cc.AnnCloneRequest, fmt.Sprintf("%s/%s", p.Namespace, p.SourceName))
cc.AddAnnotation(claim, cc.AnnPopulatorKind, cdiv1.VolumeCloneSourceRef)
if p.OwnershipLabel != "" {
AddOwnershipLabel(p.OwnershipLabel, claim, p.Owner)
}
if p.ImmediateBind {
cc.AddAnnotation(claim, cc.AnnImmediateBinding, "")
}
if p.PriorityClassName != "" {
cc.AddAnnotation(claim, cc.AnnPriorityClassName, p.PriorityClassName)
}
if err := p.Client.Create(ctx, claim); err != nil {
checkQuotaExceeded(p.Recorder, p.Owner, err)
return nil, err
}
return claim, nil
}
func hostCloneComplete(pvc *corev1.PersistentVolumeClaim) bool {
return pvc.Annotations[cc.AnnPodPhase] == string(cdiv1.Succeeded)
}