Files
Aleksei Sviridkin e9411d6b8c fix(apps): make the post-delete cleanup hooks report failure
The qdrant and harbor post-delete hooks guarded every delete with
`|| echo "WARNING: ..." >&2`, set no `-e`, and ended on an
unconditional completion message, so the container exited 0 on
every path. Helm read that as a successful hook and the
hook-succeeded delete policy removed the Job together with the pod
that carried the warning, leaving an uninstall that reclaimed
nothing indistinguishable from one that had nothing to reclaim.

Count the failures instead and set the exit code at the end, so a
failed delete does not skip the deletes that follow it. An object
that is already gone stays a success: every delete keeps
--ignore-not-found, which exits 0 in that case. This is the shape
packages/apps/mariadb already uses for the same problem.

Both hooks also consumed the output of `kubectl get` directly --
harbor by iterating it, qdrant by piping it into grep, whose status
the pipeline then reports. A listing that failed therefore arrived
as an empty list and the sweep was skipped rather than reported.
Each listing is now captured before it is used, so a listing that
failed and one that returned nothing are different events.

A hook that exits non-zero keeps its Job and pods, which is the
point: they hold the log. Give the Job one retry rather than the
Kubernetes default of six or none at all. Every delete is
idempotent, so a second attempt re-issues an API call rather than
re-running any logic, and one short backoff is what separates a
transient apiserver error from a real one -- these failures become
visible for the first time here, and a signal that fires on noise
stops being read, including on the day it is right. Six is the far
end of the same mistake: ten minutes of backoff across seven pods
outlasts the hook timeout, and Helm reports that timeout instead of
the hook's own error.

The qdrant Chainsaw suite explained its post-delete pod collector
by quoting the guard string removed here and concluding the pod is
always collected away. That is now backwards: a failed cleanup is
exactly when the pod survives and the collector is the evidence.
Rewrite the note, and the sentence in the harbor suite pointing at
it.

hack/app-cleanup-hooks_test.bats renders both scripts and runs them
against a fake kubectl. There are eight failure paths across the two
hooks -- six in harbor, two in qdrant -- and each has a case that
goes red when that one path alone is reverted to a swallowed
warning. Message assertions are anchored on the hook's own `ERROR: `
prefix, because the fake kubectl names the object in its own
diagnostic too and an unanchored match is satisfied by the fixture.
The helm-unittest suites pin the retry limit and the hook delete
policy: adding hook-failed to that annotation hands the Job back to
Helm to delete on failure and destroys the evidence this change
exists to keep, and until these asserts that reversal left both
suites green.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-08-12 18:43:02 +03:00
..

Managed Qdrant Service

Qdrant is a high-performance vector database and similarity search engine designed for AI and machine learning applications. It provides efficient storage and retrieval of high-dimensional vectors with advanced filtering capabilities, making it ideal for recommendation systems, semantic search, and RAG (Retrieval-Augmented Generation) applications.

Deployment Details

Service deploys Qdrant as a StatefulSet with automatic cluster mode when multiple replicas are configured.

storageClass is annotated as immutable in the chart schema — see docs/storage-immutability.md for the contract and which consumers enforce it.

Parameters

Common parameters

Name Description Type Value
replicas Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1. int 1
resources Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in resourcesPreset is applied. object {}
resources.cpu CPU available to each replica. quantity ""
resources.memory Memory (RAM) available to each replica. quantity ""
resourcesPreset Default sizing preset used when resources is omitted. string t1.small
size Persistent Volume Claim size available for vector data storage. quantity 10Gi
storageClass StorageClass used to store the data. string ""
external Enable external access from outside the cluster. bool false

TLS parameters

Name Description Type Value
tls TLS configuration. When omitted, the effective TLS state follows the value of external. object {}
tls.enabled Enable TLS. When unset, inherits the value of external (TLS is on when external access is enabled). Set explicitly to true or false to override. *bool null

Parameter examples and reference

resources and resourcesPreset

resources sets explicit CPU and memory configurations for each replica. When left empty, the preset defined in resourcesPreset is applied.

resources:
  cpu: 4000m
  memory: 4Gi

resourcesPreset sets named CPU and memory configurations for each replica. This setting is ignored if the corresponding resources value is set.

Presets follow a cloud-style <series>.<size> naming convention. Five series cover the full CPU-to-memory ratio range (t1 1:0.5, c1 1:1, s1 1:2, u1 1:4, m1 1:8) and each series ships eight sizes (nano through 4xlarge). The legacy flat names (nano, micro, small, medium, large, xlarge, 2xlarge) remain accepted as deprecated aliases of their 1:1 instance-type equivalents.

See docs/operations/resource-presets.md for the full size matrix and the legacy-to-instance-type mapping.