Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
183 commits
Select commit Hold shift + click to select a range
5590258
bundle: record and read deployment state via DMS with server-generate…
shreyas-goenka Jul 23, 2026
da1ed9d
bundle: read DMS authority from last_successful_version_id
shreyas-goenka Jul 24, 2026
011c092
bundle: fix DMS deployment recording bugs found in review
shreyas-goenka Jul 27, 2026
38dc082
bundle: upload DMS operations asynchronously
shreyas-goenka Jul 27, 2026
19467dc
bundle: gate experimental.record_deployment_history behind an env var
shreyas-goenka Jul 27, 2026
22ec66a
bundle: rename the record_deployment_history escape hatch to force_allow
shreyas-goenka Jul 27, 2026
d7441e4
bundle: only record net-new deployments in DMS
shreyas-goenka Jul 27, 2026
026a521
bundle: fix lint errors in the operation queue test
shreyas-goenka Jul 27, 2026
481259b
bundle: keep the create action when coalescing DMS operations
shreyas-goenka Jul 27, 2026
309a1a4
bundle: drop the dms package comment
shreyas-goenka Jul 27, 2026
211aa94
bundle: resolve the DMS deployment ID from the workspace
shreyas-goenka Jul 27, 2026
4009eb4
bundle: address review of the DMS state PR
shreyas-goenka Jul 28, 2026
70741ae
bundle: record depends_on in the state uploaded to DMS
shreyas-goenka Jul 28, 2026
386a0b6
bundle: drop the DMS state overlay check
shreyas-goenka Jul 28, 2026
efe7320
bundle: gate DMS state on a state feature flag
shreyas-goenka Jul 28, 2026
92eac95
bundle: combine queued operations into a single Create action
shreyas-goenka Jul 29, 2026
96c0826
acceptance: set MSYS_NO_PATHCONV for the DMS tests
shreyas-goenka Jul 29, 2026
b2ef0e8
acceptance: scope MSYS_NO_PATHCONV to the get-status commands
shreyas-goenka Jul 29, 2026
30adb99
bundle: drop the locks in the operation queue's close
shreyas-goenka Jul 29, 2026
8f56ef6
bundle: record operation state without redacting it
shreyas-goenka Jul 29, 2026
329886f
bundle: drop the redaction TODO from the operation recorder
shreyas-goenka Jul 29, 2026
2818d11
bundle: revert the schema annotation and tighten CompleteVersion's guard
shreyas-goenka Jul 29, 2026
b84ae7c
bundle: gate record_deployment_history off again
shreyas-goenka Jul 29, 2026
daa69e2
bundle: stop the deploy when an operation upload fails
shreyas-goenka Jul 29, 2026
2c2e209
bundle: stop applying resources once an operation upload fails
shreyas-goenka Jul 29, 2026
9329441
testserver: create the DMS deployment record on the first version
shreyas-goenka Jul 29, 2026
38b6f54
bundle: simplify the concurrency test comment
shreyas-goenka Jul 29, 2026
4f45539
bundle: trim the operation recorder tests
shreyas-goenka Jul 29, 2026
2bf49fb
bundle: send recorded state as a JSON string
shreyas-goenka Aug 3, 2026
93e95a4
bundle: send previous_version_id and display_name when recording a ve…
shreyas-goenka Aug 4, 2026
9acbecc
bundle: fix recording a destroy
shreyas-goenka Aug 4, 2026
b34ed0a
bundle: record failed operations, and upload at most 2 at a time
shreyas-goenka Aug 4, 2026
b9ca9a3
bundle: report the recorded deployment in bundle summary
shreyas-goenka Aug 5, 2026
1a05f7a
bundle: record git, workspace and mode provenance with a version
shreyas-goenka Aug 5, 2026
c08abbd
bundle: stamp the deployment and version onto jobs and pipelines
shreyas-goenka Aug 5, 2026
41c41ee
bundle: raise operation upload workers back to 8
shreyas-goenka Aug 6, 2026
af8c851
bundle: spell out how to recover from the record-deployment-history e…
shreyas-goenka Aug 6, 2026
610b71f
bundle: add a bugbash guide for deployment history recording
shreyas-goenka Aug 6, 2026
d3bda0c
bundle: report the recorded deployment after a deploy
shreyas-goenka Aug 6, 2026
45c4ed2
bundle: link to the recorded deployment after a deploy
shreyas-goenka Aug 6, 2026
a8a5148
bundle: send the prior state when recording a failed operation
shreyas-goenka Aug 6, 2026
cf2d9cd
bundle: take the id and state of a failed operation from the same record
shreyas-goenka Aug 6, 2026
015af74
bundle: stop the deployment stamp from showing as drift
shreyas-goenka Aug 6, 2026
a49f16f
bundle: group what a version records into dms.Metadata
shreyas-goenka Aug 7, 2026
37a8b94
bundle: shorten the comment on the DMS upload-failure check
shreyas-goenka Aug 7, 2026
636c9cf
bundle: stamp the deployment before planning, and keep recording afte…
shreyas-goenka Aug 7, 2026
ff96ef0
bundle: decouple InitDeploymentHistory from InitIDs
shreyas-goenka Aug 7, 2026
e1d9bf6
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 7, 2026
89369d5
bundle: fold the display-name assertions into the first-deploy test
shreyas-goenka Aug 7, 2026
02c35fd
bundle: record DMS operations from the state writes
shreyas-goenka Aug 7, 2026
3f1c296
bundle: add DATABRICKS_BUNDLE_DMS to enable deployment history recording
shreyas-goenka Aug 7, 2026
0ddb805
bundle: skip a recorded resource that was never created, and prepare …
shreyas-goenka Aug 7, 2026
42d3cb4
bundle: run the acceptance suite with deployment history recording on
shreyas-goenka Aug 7, 2026
f49c0ce
bundle: extend the DMS acceptance run across bundle/resources
shreyas-goenka Aug 7, 2026
98c50c5
bundle: drop the deployment stamp from get responses in the DMS run
shreyas-goenka Aug 7, 2026
518434f
bundle: run the resources acceptance tests with deployment history on
shreyas-goenka Aug 7, 2026
9a0a800
bundle: run the whole bundle acceptance suite with deployment history on
shreyas-goenka Aug 7, 2026
7542427
acceptance: filter the deployment stamp at the call site, not with gl…
shreyas-goenka Aug 9, 2026
1eeb57d
acceptance: cover the emptied-resource delete locally
shreyas-goenka Aug 9, 2026
2015a62
acceptance: document what nostamp actually transforms
shreyas-goenka Aug 9, 2026
6beb603
acceptance: show which job is deleted first in the depends-on test
shreyas-goenka Aug 9, 2026
170649b
bundle: make the fake service enforce that state implies a resource_id
shreyas-goenka Aug 9, 2026
d701cd9
bundle: record a recreate's intermediate delete as in-progress
shreyas-goenka Aug 9, 2026
ff6b364
bundle: cover the delete-order reversal in the dependency graph
shreyas-goenka Aug 9, 2026
125d73b
bundle: single-source the DMS resource-key prefix, fix two stale comm…
shreyas-goenka Aug 10, 2026
5f211ef
bundle: record a declined deploy as aborted, not as a failure
shreyas-goenka Aug 10, 2026
f6c564f
bundle: drop the empty-resource-id guard, which cannot happen
shreyas-goenka Aug 10, 2026
f26c7d6
bundle: correct what AllowExistingResources is for
shreyas-goenka Aug 10, 2026
c882a39
bundle: drop AllowExistingResources; opt the tests that need it out i…
shreyas-goenka Aug 10, 2026
403e659
bundle: say "unset" in the recording refusal, and table the sink tests
shreyas-goenka Aug 10, 2026
eca068d
bundle: note where the SDK bypass ends
shreyas-goenka Aug 10, 2026
5d1beb5
bundle: drop graph_test.go
shreyas-goenka Aug 10, 2026
9ef3061
bundle: decide the in-progress status at the state write
shreyas-goenka Aug 10, 2026
5edff67
bundle: merge a resource's queued operations into one upload
shreyas-goenka Aug 10, 2026
612b7e9
Merge branch 'main' of https://github.com/databricks/cli into isaac/p…
shreyas-goenka Aug 10, 2026
ac37a34
acceptance: refresh generated files after the merge
shreyas-goenka Aug 10, 2026
c0e796e
bundle: rename the recording env var, and only honour "true"
shreyas-goenka Aug 10, 2026
95c1f03
bundle: print the deployment version up front
shreyas-goenka Aug 11, 2026
eccac6b
bundle: label a recreate's second write as a recreate
shreyas-goenka Aug 11, 2026
3d0b43c
bundle: create the deployment version only once the deploy is approved
shreyas-goenka Aug 11, 2026
df67ac6
Merge branch 'main' of https://github.com/databricks/cli into isaac/p…
shreyas-goenka Aug 11, 2026
3fa81b5
acceptance: show the emptied-resource diff, and trim depends-on
shreyas-goenka Aug 11, 2026
9269882
bundle: a failure must not erase the state a resource already recorded
shreyas-goenka Aug 11, 2026
160bcf8
Merge branch 'main' of https://github.com/databricks/cli into isaac/p…
shreyas-goenka Aug 11, 2026
39b1a67
acceptance: keep Git Bash from rewriting the DMS API paths on Windows
shreyas-goenka Aug 11, 2026
705269a
acceptance: use nostamp instead of a hand-rolled jq del, and drop a d…
shreyas-goenka Aug 11, 2026
96f8cfb
Merge branch 'main' of https://github.com/databricks/cli into isaac/p…
shreyas-goenka Aug 11, 2026
7a9f4ed
acceptance: repair two tests main merged broken
shreyas-goenka Aug 11, 2026
3f610d3
bundle: upload recorded operations from one goroutine
shreyas-goenka Aug 16, 2026
ed5d9b1
bundle: queue resource keys, keep the operation in a map
shreyas-goenka Aug 17, 2026
905ff9e
bundle: correct two comments left over from the operation queue
shreyas-goenka Aug 17, 2026
6eba109
bundle: hold the deploy back when recording falls behind
shreyas-goenka Aug 17, 2026
4e33134
bundle: fail the deploy when an operation cannot be recorded
shreyas-goenka Aug 17, 2026
4deaf42
bundle: trim comments that restate the code
shreyas-goenka Aug 17, 2026
fc5465f
bundle: a coalesced failure must not revert a resource to its pre-dep…
shreyas-goenka Aug 17, 2026
162f619
bundle: build the update mask from what the service already holds
shreyas-goenka Aug 17, 2026
d3fca3b
bundle: let each operation carry its own update mask
shreyas-goenka Aug 17, 2026
9f65159
bundle: record a failed recreate as the resource being gone
shreyas-goenka Aug 17, 2026
caee7e5
acceptance: cover a failed update carrying the pre-deploy state
shreyas-goenka Aug 17, 2026
2d2ff35
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 17, 2026
138ea82
bundle: refresh a golden and drop a stale doc comment
shreyas-goenka Aug 17, 2026
a2b8014
bundle: trim the comments in opsink.go
shreyas-goenka Aug 17, 2026
9eb9106
bundle: keep the write's operation when a failure coalesces onto it
shreyas-goenka Aug 17, 2026
c7e749b
bundle: merge the update mask field by field when coalescing
shreyas-goenka Aug 17, 2026
7d8ed7e
bundle: hold every comment in this PR to three lines
shreyas-goenka Aug 18, 2026
fece1fd
bundle: fixes from a per-area review of this PR
shreyas-goenka Aug 18, 2026
77c9d2c
bundle: restore comments this PR had no business changing
shreyas-goenka Aug 18, 2026
7ea813b
bundle: record the API status and error code with a failure
shreyas-goenka Aug 18, 2026
f81833a
acceptance: show the DMS operations in the order they happen
shreyas-goenka Aug 18, 2026
e9f0512
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 18, 2026
0bdeea8
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 18, 2026
f197f62
bundle: stage operations at CreateVersion, drop CreateOperation
shreyas-goenka Aug 18, 2026
a99822b
bundle: keep deployment-history traffic out of unrelated tests
shreyas-goenka Aug 18, 2026
a788ef8
acceptance: format print_requests.py the way ruff wants
shreyas-goenka Aug 18, 2026
d1af7f6
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 18, 2026
e52d5e9
acceptance: strip the deployment stamp from tests that arrived with main
shreyas-goenka Aug 18, 2026
c6982e3
bundle/direct: drop the recorded action type
shreyas-goenka Aug 18, 2026
b15aaa6
libs/dms: own the whole DMS protocol
shreyas-goenka Aug 18, 2026
7893539
dstate: leave the state alone when a recorded envelope is malformed
shreyas-goenka Aug 18, 2026
d97c6a3
libs/dms: put every call on the client, and send each field for its o…
shreyas-goenka Aug 18, 2026
a2aae6a
libs/dms: one seam for the half the SDK cannot express
shreyas-goenka Aug 18, 2026
c9d51e8
dstate: say why the sink comes back from the locked section
shreyas-goenka Aug 18, 2026
bd964ec
direct: fix a stale comment about what a failed operation carries
shreyas-goenka Aug 18, 2026
17437dc
direct: drop sink tests that only re-test the merge
shreyas-goenka Aug 19, 2026
06fe6d7
dstate: inline the state write helpers
shreyas-goenka Aug 19, 2026
c9d95bd
libs/dms: drop Enabled from Recording
shreyas-goenka Aug 19, 2026
13cb700
libs/dms: name what the version number is stamped onto
shreyas-goenka Aug 19, 2026
615c038
libs/dms: keep the writer's tests about the sequence id
shreyas-goenka Aug 19, 2026
77bf1b4
libs/dms: leave the recorded wire format to the acceptance tests
shreyas-goenka Aug 19, 2026
a8e846b
acceptance/dms: print the recorded requests in the order they happened
shreyas-goenka Aug 19, 2026
e96181a
acceptance/dms: correct what drops an emptied resource
shreyas-goenka Aug 19, 2026
6fad8a6
acceptance/dms: show the error a refused operation gives a user
shreyas-goenka Aug 19, 2026
438788a
acceptance/dms: fold redeploy-after-destroy into record, and name res…
shreyas-goenka Aug 19, 2026
32d7d98
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 19, 2026
d019275
acceptance: record the deployment-history variant for three tests fro…
shreyas-goenka Aug 19, 2026
f79da89
libs/dms: drop both single-implementation interfaces
shreyas-goenka Aug 24, 2026
d5d2a9c
Revert "libs/dms: drop both single-implementation interfaces"
shreyas-goenka Aug 24, 2026
6c06e46
dstate: own the recording, so apply only talks to the state DB
shreyas-goenka Aug 24, 2026
7e96e2c
direct: drop the unused action parameter from Create
shreyas-goenka Aug 24, 2026
071a15c
ci: give the recording variant its own cell instead of doubling the d…
shreyas-goenka Aug 24, 2026
965be29
direct: record a delete failure where the delete failed
shreyas-goenka Aug 24, 2026
2a3cf02
direct: drop a stale comment; testserver: name the DMS handlers for w…
shreyas-goenka Aug 24, 2026
1103f3f
dstate: look the deployment up once per command
shreyas-goenka Aug 24, 2026
5420c3c
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 24, 2026
f66a144
acceptance: record the deployment-history variant for three more test…
shreyas-goenka Aug 24, 2026
3bbc475
mutator: gate deployment history on the engine, and stop looking the …
shreyas-goenka Aug 24, 2026
45edbe8
dstate: make the recorded deployment a field, not an accessor
shreyas-goenka Aug 24, 2026
afce78d
acceptance: shorten the recording variant to DMS
shreyas-goenka Aug 24, 2026
53e910e
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 24, 2026
56ab9ae
dstate: pass the DMS source through unlockedOpen
shreyas-goenka Aug 24, 2026
ae3cd7b
dms: move the operation sink into libs/dms
shreyas-goenka Aug 24, 2026
68220cf
dstate: drop the operationRecorder interface
shreyas-goenka Aug 24, 2026
1717619
dms: fold the operation writer into the sink
shreyas-goenka Aug 24, 2026
d1cd062
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 25, 2026
67d35af
dms: review fixes
shreyas-goenka Aug 25, 2026
a698604
dms: one buffered client instead of a recording and a sink
shreyas-goenka Aug 25, 2026
2d193b7
mutator: name the deployment-history lookup for what it fetches
shreyas-goenka Aug 25, 2026
cc178ff
dms: read the deployment's last version with its id
shreyas-goenka Aug 25, 2026
5a808f3
dms: the deployment owns its metadata, and the package speaks state keys
shreyas-goenka Aug 25, 2026
b9c5bac
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 25, 2026
d3fee60
dms: the buffered client is what reads the state, not a source struct
shreyas-goenka Aug 25, 2026
29f9dde
dms: say dmsBufferedClient, since there are two clients to confuse
shreyas-goenka Aug 25, 2026
70ecf84
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 25, 2026
f016043
acc: regenerate out.test.toml after merging main
shreyas-goenka Aug 25, 2026
6408d0f
dms: a recreate's delete half is PENDING, a status the API actually has
shreyas-goenka Aug 25, 2026
435683c
dms: a delete clears the state rather than recording an empty one
shreyas-goenka Aug 26, 2026
d928805
dms: a failure keeps describing a resource that is still there
shreyas-goenka Aug 27, 2026
36d4c63
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Aug 27, 2026
e90ca0d
acc: regenerate out.test.toml for the tests main added
shreyas-goenka Aug 27, 2026
7401385
acc: record the DMS reads too, so the call budget is visible
shreyas-goenka Aug 27, 2026
200b7cc
acc: cover a failed permissions update, the shape reported from dogfood
shreyas-goenka Aug 27, 2026
ba4c8a3
acc: run the DMS tests against a real workspace
shreyas-goenka Aug 30, 2026
35c171b
acc: split the DMS tests by whether their failure can be real
shreyas-goenka Aug 30, 2026
c5deafd
acc: give the pinned state path a unique name too
shreyas-goenka Aug 30, 2026
872b785
acc: leave the rest of the suite alone
shreyas-goenka Aug 30, 2026
19007bf
acc: keep only what bundle/dms needs
shreyas-goenka Aug 30, 2026
7399068
acc: make the DMS fixtures survive a shared workspace and bash 3.2
shreyas-goenka Aug 31, 2026
8d34b17
acc: restore the empty num-workers-zero golden
shreyas-goenka Aug 31, 2026
58c53d4
Merge remote-tracking branch 'origin/main' into pr6094-update
shreyas-goenka Aug 31, 2026
58257c8
Address DMS review feedback
shreyas-goenka Sep 2, 2026
ccf7a62
Merge remote-tracking branch 'origin/main' into isaac/pr6052-fixes
shreyas-goenka Sep 2, 2026
aa630e3
bundle: remove the deployment-version heartbeat and reject deploy --p…
shreyas-goenka Sep 2, 2026
02eb189
bundle: support deploy --plan under deployment history recording
shreyas-goenka Sep 3, 2026
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
105 changes: 105 additions & 0 deletions acceptance/bin/dms_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""
Read resource ids and state from the deployment metadata service.

While a bundle records deployment history the service owns the resource set, so the state file is
not where ids and state come from. The service is asked instead, which takes two lookups: the CLI
keeps no deployment id locally, and the id is the object id of the workspace node the service
registers under <state path>/resources.deployment.json (see libs/dms/resolve.go).
"""

import functools
import glob
import json
import os
import posixpath
import subprocess
import sys

sys.path.insert(0, os.path.dirname(__file__))
from print_state import get_state_file

CLI = os.environ.get("CLI", "databricks")

# Must match dms.DeploymentNodeName.
DEPLOYMENT_NODE_NAME = "resources.deployment.json"


def run_json(cmd, allow_failure=False):
"""Run cmd and parse its stdout, or return None if it fails and allow_failure is set. stderr is
captured rather than inherited: these lookups are plumbing, and a CLI warning like "no files to
sync" would otherwise land in the test output."""
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
if result.returncode != 0:
if allow_failure:
return None
raise SystemExit(f"{cmd} failed with code {result.returncode}\n{result.stdout}{result.stderr}".strip())
return json.loads(result.stdout)


def records_deployment_history():
"""Whether this run records deployment history, so the service is what to ask."""
return os.environ.get("DATABRICKS_BUNDLE_RECORD_DEPLOYMENT_HISTORY") == "true"


def get_remote_state_path(target):
"""The bundle's remote state directory.

Preferred source is the sync snapshot, because it needs no CLI call: re-running the config
load would need whatever --var and flags the test deployed with, which a helper cannot know.
A bundle with no files to sync writes no snapshot, so fall back to asking the CLI - those
bundles are the ones with nothing to parameterize."""
target_dir = os.path.dirname(get_state_file(target, False))
snapshots = glob.glob(f"{target_dir}/sync-snapshots/*.json")
if snapshots:
# One snapshot per remote path, so a test that moved its root leaves several: the newest
# is the one the last deploy used.
newest = max(snapshots, key=os.path.getmtime)
remote_path = json.loads(open(newest).read())["remote_path"]
# state and files are siblings under the bundle root.
return posixpath.join(posixpath.dirname(remote_path), "state")

args = [CLI, "bundle", "validate", "--output", "json"]
if target:
args += ["-t", target]
return run_json(args)["workspace"]["state_path"]


@functools.cache
def get_resources(target):
"""Map every recorded resource key ("jobs.foo") to its {"id", "state"}.

Empty when the bundle has no deployment recorded yet. Cached because a lookup costs three
round trips and a script asks for one resource at a time.
"""
state_path = get_remote_state_path(target)
if not state_path:
return {}

# No node means nothing has been recorded, the conclusion dms.resolveDeploymentID also draws
# from a 404 - the deployment is gone once the bundle is destroyed.
node = run_json([CLI, "workspace", "get-status", f"{state_path}/{DEPLOYMENT_NODE_NAME}"], allow_failure=True)
if not node or not node.get("object_id"):
return {}
deployment_id = node["object_id"]

result = {}
# The service pages at 50 resources; the local fake returns everything at once.
page_token = None
while True:
url = f"/api/2.0/bundle/deployments/{deployment_id}/resources"
if page_token:
url += f"?page_token={page_token}"
listed = run_json([CLI, "api", "get", url])
for resource in listed.get("resources") or []:
# The service stores state as the opaque envelope the CLI wrote (dstate.RecordedState),
# so unwrap it to the resource state itself.
envelope = json.loads(resource["state"]) if resource.get("state") else {}
result[resource["resource_key"]] = {
"id": resource.get("resource_id"),
"state": envelope.get("state") or {},
"depends_on": envelope.get("depends_on") or [],
}
page_token = listed.get("next_page_token")
if not page_token:
return result
31 changes: 30 additions & 1 deletion acceptance/bin/print_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@

import argparse
import glob
import json
import os


def records_deployment_history():
return os.environ.get("DATABRICKS_BUNDLE_RECORD_DEPLOYMENT_HISTORY") == "true"


def print_file(filename):
data = open(filename).read()
print(data, end="")
Expand Down Expand Up @@ -53,14 +58,38 @@ def get_state_file(target, backup):
return filtered[0] if filtered else result[0]


def print_recorded_state(filename, target):
"""Print the state file with its resources filled in from the deployment metadata service.

While recording, the file itself carries only the header - the service holds the resources - so
printing it raw would show an empty state and differ from the same test's non-recording run.
"""
# Imported here rather than at module level: dms_resources reads get_state_file from this module.
from dms_resources import get_resources

data = json.loads(open(filename).read())
state = {}
for key, value in sorted(get_resources(target).items()):
entry = {"__id__": value["id"], "state": value["state"]}
if value["depends_on"]:
entry["depends_on"] = value["depends_on"]
state[f"resources.{key}"] = entry
data["state"] = state
print(json.dumps(data, indent=1))


def main():
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--target")
parser.add_argument("--backup", action="store_true")
args = parser.parse_args()

for filename in get_state_files(args.target, args.backup):
if os.path.exists(filename):
if not os.path.exists(filename):
continue
if filename.endswith("resources.json") and records_deployment_history():
print_recorded_state(filename, args.target)
else:
print_file(filename)


Expand Down
21 changes: 17 additions & 4 deletions acceptance/bin/read_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

sys.path.insert(0, str(Path(__file__).parent))
from add_repl import add_repl
from dms_resources import get_resources, records_deployment_history
from print_state import get_state_file


Expand All @@ -34,6 +35,15 @@ def get_id_terraform(filename, name):
print(f"Cannot find resource with {name=}. Available: {available}", file=sys.stderr)


def get_id_recorded(target, name):
resources = get_resources(target)
for key, value in resources.items():
if key.split(".")[1] == name:
return value["id"]

print(f"Cannot find recorded resource with {name=}. Available: {list(resources)}", file=sys.stderr)


def get_id_direct(filename, name):
raw = open(filename).read()
data = json.loads(raw)
Expand All @@ -53,11 +63,14 @@ def main():
parser.add_argument("name")
args = parser.parse_args()

filename = get_state_file(args.target, args.backup)
if filename.endswith(".tfstate"):
id = get_id_terraform(filename, args.name)
if records_deployment_history():
id = get_id_recorded(args.target, args.name)
else:
id = get_id_direct(filename, args.name)
filename = get_state_file(args.target, args.backup)
if filename.endswith(".tfstate"):
id = get_id_terraform(filename, args.name)
else:
id = get_id_direct(filename, args.name)

if id:
print(id)
Expand Down
19 changes: 18 additions & 1 deletion acceptance/bin/read_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))
from dms_resources import get_resources, records_deployment_history


def print_resource_terraform(group, name, *attrs):
resource_type = "databricks_" + group[:-1]
Expand Down Expand Up @@ -50,7 +53,21 @@ def print_resource_direct(group, name, *attrs):
print(group, name, " ".join(values))


if os.environ.get("DATABRICKS_BUNDLE_ENGINE", "").startswith("direct"):
def print_resource_recorded(group, name, *attrs):
result = get_resources(None).get(f"{group}.{name}")
if result is None:
print(f"State not found for {group}.{name}")
return

state = dict(result["state"])
state.setdefault("id", result["id"])
values = [f"{x}={state.get(x)!r}" for x in attrs]
print(group, name, " ".join(values))


if records_deployment_history():
print_resource_recorded(*sys.argv[1:])
elif os.environ.get("DATABRICKS_BUNDLE_ENGINE", "").startswith("direct"):
print_resource_direct(*sys.argv[1:])
else:
print_resource_terraform(*sys.argv[1:])
18 changes: 14 additions & 4 deletions acceptance/bin/replace_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

sys.path.insert(0, str(Path(__file__).parent))
from add_repl import add_repl
from dms_resources import get_resources, records_deployment_history
from print_state import get_state_file


Expand All @@ -26,6 +27,12 @@ def iter_ids_terraform(filename):
yield r_name, id


def iter_ids_recorded(target):
for key, value in get_resources(target).items():
if value["id"]:
yield key.split(".")[1], value["id"]


def iter_ids_direct(filename):
raw = open(filename).read()
data = json.loads(raw)
Expand All @@ -44,11 +51,14 @@ def main():
parser.add_argument("--backup", action="store_true")
args = parser.parse_args()

filename = get_state_file(args.target, args.backup)
if filename.endswith(".tfstate"):
it = iter_ids_terraform(filename)
if records_deployment_history():
it = iter_ids_recorded(args.target)
else:
it = iter_ids_direct(filename)
filename = get_state_file(args.target, args.backup)
if filename.endswith(".tfstate"):
it = iter_ids_terraform(filename)
else:
it = iter_ids_direct(filename)

for name, id in it:
add_repl(id, name.upper() + "_ID")
Expand Down
4 changes: 2 additions & 2 deletions acceptance/bundle/deploy/readplan/test.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Saved plans don't carry the deployment stamp. Applying one plans an update on the next run.
# See dms_no_readplan in acceptance/bundle/test.toml.
# Dumps post-deploy state/plan, which carry the DMS deployment stamp under recording (applied at
# deploy, not saved in the plan). deploy --plan recording is covered by bundle/dms, so opt out here.
EnvMatrix.DMS = [""]
2 changes: 1 addition & 1 deletion acceptance/bundle/deploy/wal/header-only-wal/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Resources: 1 created, 0 changed, 0 deleted, 0 unchanged

>>> errcode assert_not_exists.py .databricks/bundle/default/resources.json.wal

>>> errcode cat .databricks/bundle/default/resources.json
>>> errcode print_state.py
{
"serial": 1,
"state_keys": [
Expand Down
2 changes: 1 addition & 1 deletion acceptance/bundle/deploy/wal/header-only-wal/script
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ title "Third deploy (must recover and succeed, not blocked by the leftover WAL)"
trace errcode $CLI bundle deploy --force-lock

trace errcode assert_not_exists.py .databricks/bundle/default/resources.json.wal
trace errcode cat .databricks/bundle/default/resources.json | jq -S '{serial: .serial, state_keys: (.state | keys)}'
trace errcode print_state.py | jq -S '{serial: .serial, state_keys: (.state | keys)}'
10 changes: 10 additions & 0 deletions acceptance/bundle/dms/declined-deploy/databricks.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
bundle:
name: dms-declined-deploy-$UNIQUE_NAME
experimental:
record_deployment_history: true

resources:
schemas:
foo:
name: dms_declined_deploy_schema_$UNIQUE_NAME
catalog_name: main
7 changes: 7 additions & 0 deletions acceptance/bundle/dms/declined-deploy/out.requests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"method": "DELETE",
"path": "/api/2.1/unity-catalog/catalogs/dms_other_[UNIQUE_NAME]",
"q": {
"force": "true"
}
}
3 changes: 3 additions & 0 deletions acceptance/bundle/dms/declined-deploy/out.test.toml

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

Loading
Loading