Skip to content

AIR CLI Integration: image wiring (registered image used with client side) - #6165

Open
riddhibhagwat-db wants to merge 6 commits into
air-clifrom
air-integration-m6-2
Open

AIR CLI Integration: image wiring (registered image used with client side)#6165
riddhibhagwat-db wants to merge 6 commits into
air-clifrom
air-integration-m6-2

Conversation

@riddhibhagwat-db

Copy link
Copy Markdown
Contributor

Changes

Wires a registered Docker image end-to-end through air run, so an image registered with air register-image is actually verified and used by a run.

  • environment.docker_image now parses tag_policy, credentials_scope, and credentials_key (previously only url), with the same validation as the Python config: tag_policy must be auto or latest, and the credential scope/key must be provided together.
  • New rundockerimage.go adds the pre-submit checks ported from the Python cli/docker_utils.py:
    • require an existing registration, blocking while it is still PENDING/IMPORTING; a missing or FAILED registration errors with air register-image guidance.
    • under tag_policy: latest, re-register so the run picks up the tag's newest digest, using the configured credentials or else the local Docker config.
  • submitWorkload runs those checks after the cheap workspace calls but before any artifact upload, and buildSubmitPayload sets ai_runtime_task.docker_image_url.

Why

air run previously parsed environment.docker_image.url and runconfig_launch.go carried a TODO saying full support needed image registration, which landed in the parent PR.

Tests

  • Unit tests for the preflight helpers: available / not-registered / FAILED / waits-while-importing, auto not re-registering vs latest re-registering, credential auto-discovery (asserting the secret reference rides the POST), storage-denied reporting that cause rather than docker login, and an explicitly-named secret being rejected without an anonymous retry.
  • Config validation tests for tag_policy values, credential pairing, credentials rejected under the default policy, and a blank scope not counting as set.
  • Two buildSubmitPayload tests (with and without a docker image) are included but can't compile until the SDK field lands. Everything else was verified green (go test, golangci-lint, gofmt) with that one field removed.
  • No acceptance coverage for the run path yet, since the test binary can't build, will add after SDK bump

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

Based on git history, these people are best suited to review:

  • @vinchenzo-db -- recent work in experimental/air/cmd/

Eligible reviewers: @apeforest, @ben-hansen-db, @bfontain, @lu-wang-dl, @maggiewang-db, @panchalhp-db, @pardis-beikzadeh-db

Suggestions based on git history. See OWNERS for ownership rules.

environment.docker_image parsed only `url`, dropping the tag_policy and
credential fields the Python config supports. Add TagPolicy, CredentialsScope,
and CredentialsKey with the same validation: tag_policy must be auto or latest,
and the credential scope/key must be provided together.

Also drop the stale TODO on dockerImageURL (image registration has landed) and
add a dockerImage() accessor for the block.

Nothing consumes these yet; the run preflight and submit plumbing follow.

Co-authored-by: Isaac
Port the pre-submit image checks from the Python cli/docker_utils.py into
rundockerimage.go:

  - waitForRegisteredImage requires an existing registration and blocks while it
    is still PENDING/IMPORTING. A missing or FAILED registration is an error
    pointing at `air register-image`, so a run fails here with a clear cause
    rather than deep in the launch/pod stage.
  - resolveLatestDockerImage re-registers when tag_policy is "latest" so the run
    picks up the tag's newest digest, using the config's credentials when set and
    otherwise the local Docker config, with the same stale-credential anonymous
    retry as `air register-image`.
  - prepareDockerImage sequences the two.

Nothing calls prepareDockerImage yet; the submit wiring follows.

Co-authored-by: Isaac
Complete the end-to-end path: `air run` now verifies the custom image before
doing any upload work, and passes it to the Jobs submit call.

  - submitWorkload calls prepareDockerImage right after the idempotency token is
    resolved, so an unregistered, failed, or still-importing image fails (or
    blocks) before artifacts are uploaded.
  - buildSubmitPayload sets ai_runtime_task.docker_image_url from
    environment.docker_image.url, matching the Python jobs client.

NOTE: this does not compile against databricks-sdk-go v0.165.0 —
jobs.AiRuntimeTask does not model docker_image_url yet. The field is written as
DockerImageUrl in anticipation of the pending SDK PR; bump the SDK in go.mod once
it merges and this builds as-is. Everything else in the branch (config parsing
and the preflight helpers) was verified green with the field removed.

Co-authored-by: Isaac
Trim the docker-image comments to what the code does not already say.

Co-authored-by: Isaac
Review fixes:

  - The "registration in progress" and "re-resolving" messages used log.Infof,
    which is silent at the CLI's default WARN level, so a run could block for up
    to imageReadyTimeout with no output at all. Print them with cmdio.LogString
    like the rest of `air run`.
  - dockerImageConfig.validate checked a trimmed URL but stored the raw one, so
    a padded `url:` passed validation and then rode the submitted task untrimmed.
    Trim URL and the credential fields in place, matching the Python validator;
    this also stops a blank credentials_scope from suppressing discovery.
  - Move the preflight below ensureExperimentDirectory/userWorkspaceDir so a bad
    experiment directory fails immediately instead of after a tag_policy=latest
    refresh, while still preceding any upload.

Adds coverage for the two previously-unexercised branches: credential
auto-discovery on the latest path (asserting the reference rides the POST) and
the storage-denied path (asserting the error names that cause, not `docker
login`).

Co-authored-by: Isaac
  - Only retry anonymously when the credentials were auto-discovered. The gate
    was `scope != ""`, so credentials the user configured explicitly were also
    retried away and then blamed on a missing `docker login`. Carry the
    distinction in an imageCredentials struct; an explicitly-named secret that is
    rejected now reports that secret instead.
  - Reject docker_image.credentials_scope/credentials_key under the default tag
    policy. They are only consulted when re-resolving the tag, so accepting them
    otherwise silently ignored them.
  - Note on waitForRegisteredImage that Python's :validateImageAccess preflight
    is deliberately not ported and should be implemented in the backend, so every
    client benefits and the CLI does not pay a round trip per submit.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 1f550e7

Run: 30961775196

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 3 79 11 0:50
💚​ aws windows 3 79 11 1:03
💚​ azure linux 3 78 11 0:51
💚​ azure windows 3 78 11 0:50
🙈​ gcp linux 1 79 11 0:56
🙈​ gcp windows 1 79 11 0:54
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants