You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Feature] Add opt-in post-upgrade job to trigger MLRun DB migrations - #325
Adds an optional Job that triggers MLRun DB migrations automatically after helm upgrade, so users no longer have to run mlrun.get_run_db().trigger_migrations() by hand.
The Job is rendered only when mlrunMigrations.enabled=true, mlrun.enabled=true and the release is an upgrade (.Release.IsUpgrade).
Before sending POST /api/v1/operations/migrations, it makes sure the new API chief is up: it waits for the mlrun-api-chief rollout, for every chief pod to run the expected mlrun.api.image, and for /api/v1/client-spec to report the expected version.
It is a regular release resource, not a Helm hook, so long migrations can't make helm upgrade time out (also with --wait, unless --wait-for-jobs is set).
It is disabled by default, so existing installations are not affected.
Guarded by {{- if and .Values.mlrun.enabled .Values.mlrunMigrations.enabled .Release.IsUpgrade }}.
Has no helm.sh/hook annotations. The revision suffix creates a fresh Job on every upgrade, because Job specs are immutable. Helm deletes the previous revision's Job because it is no longer part of the release.
Single container (alpine/kubectl:1.33.4, sh + curl):
Waits for kubectl rollout status deployment/mlrun-api-chief.
Waits until every chief pod, including terminating ones, runs exactly mlrun.api.image.
Polls GET /api/v1/client-spec until the chief reports the expected version.
Sends POST /api/v1/operations/migrations. A 200 means no migrations were needed and the Job succeeds. A 202 returns a background task, which the Job polls at GET /api/v1/background-tasks/<name> until it is succeeded or failed. Any other status fails the Job.
restartPolicy: Never, backoffLimit and activeDeadlineSeconds come from values.
There is no ttlSecondsAfterFinished, so the Job and its pods stay for inspection until the next upgrade replaces them.
charts/mlrun-ce/templates/mlrun-migrations/rbac.yaml (new): ServiceAccount, Role and RoleBinding <release>-mlrun-migrations, with read-only get/list/watch on deployments and replicasets and get/list on pods. They are rendered whenever mlrun.enabled and mlrunMigrations.enabled are true, including on install.
charts/mlrun-ce/templates/NOTES.txt: on upgrades with the feature enabled, prints the kubectl logs -f job/<release>-mlrun-migrations-<revision> command.
charts/mlrun-ce/templates/_helpers.tpl: new helpers mlrun-ce.mlrun.api.chief.fullname, mlrun-ce.mlrun.api.image, mlrun-ce.mlrunMigrations.labels and mlrun-ce.mlrunMigrations.selectorLabels.
charts/mlrun-ce/values.yaml: new top-level mlrunMigrations block with enabled: false, expectedVersion: "" (defaults to mlrun.api.image.tag), pollIntervalSeconds: 5, timeoutSeconds: 3600, backoffLimit: 2, kubectlImage (alpine/kubectl:1.33.4) and resources.
admin_installation_values.yaml, non_admin_installation_values.yaml and non_admin_cluster_ip_installation_values.yaml: added mlrunMigrations.enabled: false.
charts/mlrun-ce/README.md: the "Triggering DB Migrations" section now documents the automatic option and how to check the Job result.
AGENTS.md: added the mlrun-migrations/ template directory and a row in the Component Dependency Map.
charts/mlrun-ce/Chart.yaml: version bumped from 0.12.1-rc.4 to 0.12.1-rc.5.
✅ Checklist
I have tested the changes in this PR
I confirmed whether my changes require a change in documentation and if so, I created another PR in MLRun for the relevant documentation.
I confirmed whether my changes require changes in QA tests, for example: credentials changes, resources naming change and if so, I updated the relevant Jira ticket for QA.
I increased the Chart version in charts/mlrun-ce/Chart.yaml.
I confirmed that the installation works both on a local Docker Desktop environment and on a real cluster when using the required prerequisites.
If installation issues were found, I updated the relevant Jira ticket with the issue and steps to reproduce, or updated the prerequisites documentation if the issue is related to missing or outdated prerequisites.
helm lint charts/mlrun-ce passes. ct lint was not run because ct is not installed locally.
helm template --set mlrunMigrations.enabled=true renders only the RBAC on install. With --is-upgrade it also renders the Job mlrun-mlrun-migrations-<revision> without hook annotations. Nothing renders in admin mode (mlrun.enabled: false) or when the flag is off.
The rendered values resolve from the mlrun sub-chart defaults: EXPECTED_IMAGE=quay.io/mlrun/mlrun-api:1.12.0, EXPECTED_VERSION=1.12.0 and MLRUN_CHIEF_URL=http://mlrun-api-chief.<namespace>.svc.cluster.local:8080. Overriding mlrun.api.image.tag updates both the image and the version.
sh -n syntax check of the rendered script passes.
Confirmed that alpine/kubectl:1.33.4 ships sh and curl but not bash or jq.
--wait behaviour was checked against the Helm and kstatus source. In both the default and the legacy wait modes, Helm does not wait for a running Job unless --wait-for-jobs is set.
The API contract was checked against the mlrun source (1.12.x). After an upgrade that needs migrations, the chief starts in waiting_for_migrations and only allows healthz, client-spec, migrations and background-tasks. POST /operations/migrations returns 200, 202 with a background task, or 412 when migrations already failed.
Not yet tested: the sh/curl script end to end, and a real upgrade that requires migrations.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The migration Job can exceed Kubernetes name limits for valid Helm releases, while the documented value-reuse approach and hardcoded naming assumptions can cause rendering failures or prevent migrations.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Existing-release upgrades can fail to render when migration values are absent, and incorrect chief resource naming can prevent migrations from running.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The migration job must write parsing diagnostics to stderr because command substitution captures stdout and set -e exits without logging the error or response body.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Write JSON parsing errors to stderr for job diagnostics
Write failure diagnostics to stderr. Calls such as version=$(json_string version) capture stdout, including this error message when a JSON key is missing; set -e then exits the script without printing the captured output. The Job therefore fails without logging the parsing error or response body, making malformed or changed API responses difficult to diagnose.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because the migrations Job sends no credentials to protected routes, causing HTTP 401 failures and leaving migrations untriggered when authentication is enabled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📝 Description
Adds an optional Job that triggers MLRun DB migrations automatically after
helm upgrade, so users no longer have to runmlrun.get_run_db().trigger_migrations()by hand.The Job is rendered only when
mlrunMigrations.enabled=true,mlrun.enabled=trueand the release is an upgrade (.Release.IsUpgrade).Before sending
POST /api/v1/operations/migrations, it makes sure the new API chief is up: it waits for themlrun-api-chiefrollout, for every chief pod to run the expectedmlrun.api.image, and for/api/v1/client-specto report the expected version.It is a regular release resource, not a Helm hook, so long migrations can't make
helm upgradetime out (also with--wait, unless--wait-for-jobsis set).It is disabled by default, so existing installations are not affected.
🛠️ Changes Made
charts/mlrun-ce/templates/mlrun-migrations/migrations-job.yaml(new): Job<release>-mlrun-migrations-<revision>.{{- if and .Values.mlrun.enabled .Values.mlrunMigrations.enabled .Release.IsUpgrade }}.helm.sh/hookannotations. The revision suffix creates a fresh Job on every upgrade, because Job specs are immutable. Helm deletes the previous revision's Job because it is no longer part of the release.alpine/kubectl:1.33.4,sh+curl):kubectl rollout status deployment/mlrun-api-chief.mlrun.api.image.GET /api/v1/client-specuntil the chief reports the expected version.POST /api/v1/operations/migrations. A 200 means no migrations were needed and the Job succeeds. A 202 returns a background task, which the Job polls atGET /api/v1/background-tasks/<name>until it issucceededorfailed. Any other status fails the Job.restartPolicy: Never,backoffLimitandactiveDeadlineSecondscome from values.ttlSecondsAfterFinished, so the Job and its pods stay for inspection until the next upgrade replaces them.charts/mlrun-ce/templates/mlrun-migrations/rbac.yaml(new): ServiceAccount, Role and RoleBinding<release>-mlrun-migrations, with read-onlyget/list/watchondeploymentsandreplicasetsandget/listonpods. They are rendered whenevermlrun.enabledandmlrunMigrations.enabledare true, including on install.charts/mlrun-ce/templates/NOTES.txt: on upgrades with the feature enabled, prints thekubectl logs -f job/<release>-mlrun-migrations-<revision>command.charts/mlrun-ce/templates/_helpers.tpl: new helpersmlrun-ce.mlrun.api.chief.fullname,mlrun-ce.mlrun.api.image,mlrun-ce.mlrunMigrations.labelsandmlrun-ce.mlrunMigrations.selectorLabels.charts/mlrun-ce/values.yaml: new top-levelmlrunMigrationsblock withenabled: false,expectedVersion: ""(defaults tomlrun.api.image.tag),pollIntervalSeconds: 5,timeoutSeconds: 3600,backoffLimit: 2,kubectlImage(alpine/kubectl:1.33.4) andresources.admin_installation_values.yaml,non_admin_installation_values.yamlandnon_admin_cluster_ip_installation_values.yaml: addedmlrunMigrations.enabled: false.charts/mlrun-ce/README.md: the "Triggering DB Migrations" section now documents the automatic option and how to check the Job result.AGENTS.md: added themlrun-migrations/template directory and a row in the Component Dependency Map.charts/mlrun-ce/Chart.yaml: version bumped from0.12.1-rc.4to0.12.1-rc.5.✅ Checklist
charts/mlrun-ce/Chart.yaml.🧪 Testing
helm lint charts/mlrun-cepasses.ct lintwas not run becausectis not installed locally.helm template --set mlrunMigrations.enabled=truerenders only the RBAC on install. With--is-upgradeit also renders the Jobmlrun-mlrun-migrations-<revision>without hook annotations. Nothing renders in admin mode (mlrun.enabled: false) or when the flag is off.EXPECTED_IMAGE=quay.io/mlrun/mlrun-api:1.12.0,EXPECTED_VERSION=1.12.0andMLRUN_CHIEF_URL=http://mlrun-api-chief.<namespace>.svc.cluster.local:8080. Overridingmlrun.api.image.tagupdates both the image and the version.sh -nsyntax check of the rendered script passes.alpine/kubectl:1.33.4shipsshandcurlbut notbashorjq.--waitbehaviour was checked against the Helm and kstatus source. In both the default and thelegacywait modes, Helm does not wait for a running Job unless--wait-for-jobsis set.waiting_for_migrationsand only allowshealthz,client-spec,migrationsandbackground-tasks.POST /operations/migrationsreturns 200, 202 with a background task, or 412 when migrations already failed.sh/curlscript end to end, and a real upgrade that requires migrations.🔗 References
server/py/services/api/api/endpoints/operations.py(POST /operations/migrations)🚨 Breaking Changes?