Skip to content
Draft
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
5 changes: 5 additions & 0 deletions images/dvcr-artifact/pkg/uploader/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ func (app *uploadServerApp) healthzHandler(w http.ResponseWriter, _ *http.Reques
}

func (app *uploadServerApp) validateShouldHandleRequest(w http.ResponseWriter, r *http.Request) bool {
if r.Method == http.MethodGet {
w.WriteHeader(http.StatusOK)
return false
}

if r.Method != http.MethodPost && r.Method != http.MethodPut {
w.WriteHeader(http.StatusNotFound)
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ func MakeOwnerReference(ing *netv1.Ingress) metav1.OwnerReference {
Controller: &isController,
}
}

// IsIngressReady returns true if the load-balancer has at least one ingress point in the status; otherwise, it returns false.
func IsIngressReady(ing *netv1.Ingress) bool {
return len(ing.Status.LoadBalancer.Ingress) != 0
}
11 changes: 11 additions & 0 deletions images/virtualization-artifact/pkg/common/pod/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ func IsPodStarted(pod *corev1.Pod) bool {
return true
}

// IsPodReady returns true if the pod's `Ready` condition status is true; otherwise, it returns false.
func IsPodReady(pod *corev1.Pod) bool {
for _, c := range pod.Status.Conditions {
if c.Type == corev1.PodReady && c.Status == corev1.ConditionTrue {
return true
}
}

return false
}

// IsPodComplete returns true if a Pod is in 'Succeeded' phase, false if not.
func IsPodComplete(pod *corev1.Pod) bool {
return pod != nil && pod.Status.Phase == corev1.PodSucceeded
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ type Stat interface {
GetDVCRImageName(pod *corev1.Pod) string
GetDownloadSpeed(ownerUID types.UID, pod *corev1.Pod) *v1alpha2.StatusSpeed
GetProgress(ownerUID types.UID, pod *corev1.Pod, prevProgress string, opts ...service.GetProgressOption) string
IsUploaderReady(pod *corev1.Pod, svc *corev1.Service, ing *netv1.Ingress) bool
IsUploaderReady(svc *corev1.Service, ing *netv1.Ingress) (bool, error)
IsUploadStarted(ownerUID types.UID, pod *corev1.Pod) bool
CheckPod(pod *corev1.Pod) error
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,27 @@ func (ds UploadDataSource) Sync(ctx context.Context, cvi *v1alpha2.ClusterVirtua
}

log.Info("Provisioning...", "progress", cvi.Status.Progress, "pod.phase", pod.Status.Phase)
case ds.statService.IsUploaderReady(pod, svc, ing):
cb.
Status(metav1.ConditionFalse).
Reason(cvicondition.WaitForUserUpload).
Message("Waiting for the user upload.")

cvi.Status.Phase = v1alpha2.ImageWaitForUserUpload
cvi.Status.Target.RegistryURL = ds.statService.GetDVCRImageName(pod)
cvi.Status.ImageUploadURLs = &v1alpha2.ImageUploadURLs{
External: ds.uploaderService.GetExternalURL(ctx, ing),
InCluster: ds.uploaderService.GetInClusterURL(ctx, svc),
case podutil.IsPodReady(pod):
isUploderReady, err := ds.statService.IsUploaderReady(svc, ing)
if err != nil {
return reconcile.Result{}, err
}

log.Info("Waiting for the user upload", "pod.phase", pod.Status.Phase)
if isUploderReady {
cb.
Status(metav1.ConditionFalse).
Reason(cvicondition.WaitForUserUpload).
Message("Waiting for the user upload.")

cvi.Status.Phase = v1alpha2.ImageWaitForUserUpload
cvi.Status.Target.RegistryURL = ds.statService.GetDVCRImageName(pod)
cvi.Status.ImageUploadURLs = &v1alpha2.ImageUploadURLs{
External: ds.uploaderService.GetExternalURL(ctx, ing),
InCluster: ds.uploaderService.GetInClusterURL(ctx, svc),
}

log.Info("Waiting for the user upload", "pod.phase", pod.Status.Phase)
}
default:
cb.
Status(metav1.ConditionFalse).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import (
"github.com/deckhouse/virtualization-controller/pkg/common/humanize_bytes"
"github.com/deckhouse/virtualization-controller/pkg/common/imageformat"
"github.com/deckhouse/virtualization-controller/pkg/common/percent"
podutil "github.com/deckhouse/virtualization-controller/pkg/common/pod"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
"github.com/deckhouse/virtualization-controller/pkg/controller/monitoring"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
Expand Down Expand Up @@ -272,14 +271,23 @@ func (s StatService) IsImportStarted(ownerUID types.UID, pod *corev1.Pod) bool {
return progress.ProgressRaw() > 0
}

func (s StatService) IsUploaderReady(pod *corev1.Pod, svc *corev1.Service, ing *netv1.Ingress) bool {
if pod == nil || svc == nil || ing == nil {
return false
func (s StatService) IsUploaderReady(svc *corev1.Service, ing *netv1.Ingress) (bool, error) {
if svc == nil || ing == nil {
return false, nil
}

ingressIsOK := ing.Annotations[annotations.AnnUploadPath] != "" || ing.Annotations[annotations.AnnUploadURLDeprecated] != ""
uploadURL, ok := ing.Annotations[annotations.AnnUploadURL]
if ok {
response, err := http.Get(uploadURL)
if err != nil {
return false, fmt.Errorf("failed to get upload service status: %w", err)
}
if response.StatusCode == http.StatusOK {
return true, nil
}
}

return podutil.IsPodRunning(pod) && podutil.IsPodStarted(pod) && ingressIsOK
return false, nil
}

func (s StatService) IsUploadStarted(ownerUID types.UID, pod *corev1.Pod) bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand All @@ -36,6 +37,12 @@ const (
destinationAuthVol = "dvcr-secret-vol"
)

// These constants can't be imported from "images/dvcr-artifact/pkg/uploader/uploader.go" due to conflicts with the CDI version.
const (
healthzPort = 8080
healthzPath = "/healthz"
)

type Pod struct {
PodSettings *PodSettings
Settings *Settings
Expand Down Expand Up @@ -151,6 +158,15 @@ func (p *Pod) makeUploaderContainerSpec() *corev1.Container {
SecurityContext: &corev1.SecurityContext{
ReadOnlyRootFilesystem: ptr.To(true),
},
ReadinessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: healthzPath,
Port: intstr.FromInt(healthzPort),
},
},
InitialDelaySeconds: 5,
},
}

if p.PodSettings.ResourceRequirements != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,29 +190,35 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (
}

if !ds.statService.IsUploadStarted(vd.GetUID(), pod) {
if ds.statService.IsUploaderReady(pod, svc, ing) {
log.Info("Waiting for the user upload", "pod.phase", pod.Status.Phase)

vd.Status.Phase = v1alpha2.DiskWaitForUserUpload
cb.
Status(metav1.ConditionFalse).
Reason(vdcondition.WaitForUserUpload).
Message("Waiting for the user upload.")
vd.Status.ImageUploadURLs = &v1alpha2.ImageUploadURLs{
External: ds.uploaderService.GetExternalURL(ctx, ing),
InCluster: ds.uploaderService.GetInClusterURL(ctx, svc),
if podutil.IsPodReady(pod) {
isUploaderReady, err := ds.statService.IsUploaderReady(svc, ing)
if err != nil {
return reconcile.Result{}, err
}
if isUploaderReady {
log.Info("Waiting for the user upload", "pod.phase", pod.Status.Phase)

vd.Status.Phase = v1alpha2.DiskWaitForUserUpload
cb.
Status(metav1.ConditionFalse).
Reason(vdcondition.WaitForUserUpload).
Message("Waiting for the user upload.")
vd.Status.ImageUploadURLs = &v1alpha2.ImageUploadURLs{
External: ds.uploaderService.GetExternalURL(ctx, ing),
InCluster: ds.uploaderService.GetInClusterURL(ctx, svc),
}
} else {
log.Info("Waiting for the uploader to be ready to process the user's upload", "pod.phase", pod.Status.Phase)

vd.Status.Phase = v1alpha2.DiskPending
cb.
Status(metav1.ConditionFalse).
Reason(vdcondition.ProvisioningNotStarted).
Message(fmt.Sprintf("Waiting for the uploader %q to be ready to process the user's upload.", pod.Name))
}
} else {
log.Info("Waiting for the uploader to be ready to process the user's upload", "pod.phase", pod.Status.Phase)

vd.Status.Phase = v1alpha2.DiskPending
cb.
Status(metav1.ConditionFalse).
Reason(vdcondition.ProvisioningNotStarted).
Message(fmt.Sprintf("Waiting for the uploader %q to be ready to process the user's upload.", pod.Name))
return reconcile.Result{RequeueAfter: time.Second}, nil
}

return reconcile.Result{RequeueAfter: time.Second}, nil
}

log.Info("Provisioning to DVCR is in progress", "podPhase", pod.Status.Phase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type Stat interface {
step.WaitForPodStepStat
step.ReadyContainerRegistryStepStat
IsUploadStarted(ownerUID types.UID, pod *corev1.Pod) bool
IsUploaderReady(pod *corev1.Pod, svc *corev1.Service, ing *netv1.Ingress) bool
IsUploaderReady(svc *corev1.Service, ing *netv1.Ingress) (bool, error)
GetDownloadSpeed(ownerUID types.UID, pod *corev1.Pod) *v1alpha2.StatusSpeed
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading