Skip to content
Open
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 @@ -57,6 +57,9 @@ type Uploader interface {
Unprotect(ctx context.Context, sup supplements.Generator, pod *corev1.Pod, svc *corev1.Service, ing *netv1.Ingress) error
GetExternalURL(ctx context.Context, ing *netv1.Ingress) string
GetInClusterURL(ctx context.Context, svc *corev1.Service) string
EnsureIngress(ctx context.Context, obj client.Object, sup supplements.Generator) (*netv1.Ingress, error)
IngressHostDrifted(ing *netv1.Ingress) bool
ExpectedIngressHost() string
}

type Stat interface {
Expand Down

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 @@ -101,6 +101,22 @@ func (ds UploadDataSource) Sync(ctx context.Context, cvi *v1alpha2.ClusterVirtua
return reconcile.Result{}, err
}

// Sync the uploader Ingress host before the readiness probe:
// IsUploaderReady HTTPS-probes the Ingress host, so a stale host (e.g. after
// publicDomainTemplate changed) makes readiness fail with a TLS error.
// Initial creation is handled by Start, so skip when the pod is absent.
if pod != nil && ds.uploaderService.IngressHostDrifted(ing) {
var oldHost string
if ing != nil && len(ing.Spec.Rules) > 0 {
oldHost = ing.Spec.Rules[0].Host
}
log.Info("Syncing uploader Ingress: host drifted", "old", oldHost, "new", ds.uploaderService.ExpectedIngressHost())
ing, err = ds.uploaderService.EnsureIngress(ctx, cvi, supgen)
if err != nil {
return reconcile.Result{}, err
}
}

isUploaderReady, err := ds.statService.IsUploaderReady(pod, svc, ing, tlsSecret)
if err != nil {
return reconcile.Result{}, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ func (s UploaderService) Start(
return err
}

ing, err := uploader.NewIngress(s.getIngressSettings(ownerRef, sup)).Create(ctx, s.client)
if err != nil && !k8serrors.IsAlreadyExists(err) {
ing, err := uploader.NewIngress(s.getIngressSettings(ownerRef, sup)).Apply(ctx, s.client)
if err != nil {
return err
}

Expand Down Expand Up @@ -275,6 +275,41 @@ func (s UploaderService) getServiceSettings(ownerRef *metav1.OwnerReference, sup
}
}

// EnsureIngress reconciles the uploader Ingress with server-side apply and
// returns the fresh object. It is cheap: callers should invoke it only when the
// already-fetched Ingress host drifted from the configured UPLOADER_INGRESS_HOST
// (e.g. after publicDomainTemplate change). When there is no drift, skip the call:
// Apply is a no-op only when managed fields already match, but avoiding the
// round-trip entirely keeps steady-state reconcile free of extra writes.
func (s UploaderService) EnsureIngress(ctx context.Context, obj client.Object, sup supplements.Generator) (*netv1.Ingress, error) {
ownerRef := metav1.NewControllerRef(obj, obj.GetObjectKind().GroupVersionKind())
ing, err := uploader.NewIngress(s.getIngressSettings(ownerRef, sup)).Apply(ctx, s.client)
if err != nil {
return nil, err
}
if err := supplements.EnsureForIngress(ctx, s.client, sup, ing, s.dvcrSettings); err != nil {
return nil, err
}
return ing, nil
}

// ExpectedIngressHost returns the host the uploader Ingress should expose,
// derived from UPLOADER_INGRESS_HOST (i.e. the rendered publicDomainTemplate).
func (s UploaderService) ExpectedIngressHost() string {
return s.dvcrSettings.UploaderIngressSettings.Host
}

// IngressHostDrifted reports whether the given Ingress host differs from the
// configured one. An absent Ingress (nil) or an Ingress without rules is
// treated as drift so callers fall back to EnsureIngress / Start.
func (s UploaderService) IngressHostDrifted(ing *netv1.Ingress) bool {
expected := s.ExpectedIngressHost()
if ing == nil || len(ing.Spec.Rules) == 0 {
return true
}
return ing.Spec.Rules[0].Host != expected
}

func (s UploaderService) getIngressSettings(ownerRef *metav1.OwnerReference, sup supplements.Generator) *uploader.IngressSettings {
uploaderIng := sup.UploaderIngress()
uploaderSvc := sup.UploaderService()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,21 @@ func NewIngress(settings *IngressSettings) *Ingress {
return &Ingress{settings}
}

func (i *Ingress) Create(ctx context.Context, client client.Client) (*netv1.Ingress, error) {
ing := i.makeSpec()
// Apply reconciles the Ingress using server-side apply: it creates the Ingress
// if absent and updates spec/annotations when they drift (e.g. when
// publicDomainTemplate changes UPLOADER_INGRESS_HOST). Field ownership is
// stable across controller restarts.
const fieldOwner = "virtualization-controller"

if err := client.Create(ctx, ing); err != nil {
func (i *Ingress) Apply(ctx context.Context, c client.Client) (*netv1.Ingress, error) {
desired := i.makeSpec()
desired.SetGroupVersionKind(netv1.SchemeGroupVersion.WithKind("Ingress"))

if err := c.Patch(ctx, desired, client.Apply, client.FieldOwner(fieldOwner)); err != nil {
return nil, err
}

return ing, nil
return desired, nil
}

// makeSpec fills Ingress structure with uploader settings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *v1alpha2.VirtualDisk) (
return reconcile.Result{}, err
}

// Sync the uploader Ingress host before the readiness probe:
// IsUploaderReady HTTPS-probes the Ingress host, so a stale host (e.g. after
// publicDomainTemplate changed) makes readiness fail with a TLS error.
// Initial creation is handled by Start, so skip when the pod is absent.
if pod != nil && ds.uploaderService.IngressHostDrifted(ing) {
var oldHost string
if ing != nil && len(ing.Spec.Rules) > 0 {
oldHost = ing.Spec.Rules[0].Host
}
log.Info("Syncing uploader Ingress: host drifted", "old", oldHost, "new", ds.uploaderService.ExpectedIngressHost())
ing, err = ds.uploaderService.EnsureIngress(ctx, vd, supgen)
if err != nil {
return reconcile.Result{}, err
}
}

isUploaderReady, err := ds.statService.IsUploaderReady(pod, svc, ing, tlsSecret)
if err != nil {
return reconcile.Result{}, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type Uploader interface {
Unprotect(ctx context.Context, sup supplements.Generator, pod *corev1.Pod, svc *corev1.Service, ing *netv1.Ingress) error
GetExternalURL(ctx context.Context, ing *netv1.Ingress) string
GetInClusterURL(ctx context.Context, svc *corev1.Service) string
EnsureIngress(ctx context.Context, obj client.Object, sup supplements.Generator) (*netv1.Ingress, error)
IngressHostDrifted(ing *netv1.Ingress) bool
ExpectedIngressHost() string
}

type Stat interface {
Expand Down
Loading
Loading