Skip to content

Commit 4c6ba0b

Browse files
committed
wip
1 parent ba74944 commit 4c6ba0b

File tree

8 files changed

+123
-13
lines changed

8 files changed

+123
-13
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resources:
2+
volumes:
3+
foo:
4+
catalog_name: mycatalog
5+
schema_name: myschema
6+
name: myname

acceptance/bundle/resource_deps/remote_delete_volume/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
>>> [CLI] bundle deploy
3+
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
4+
Deploying resources...
5+
Updating deployment state...
6+
Deployment complete!
7+
8+
>>> [CLI] volumes delete mycatalog.myschema.myname
9+
10+
>>> [CLI] bundle plan
11+
create volumes.foo
12+
13+
Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trace $CLI bundle deploy
2+
trace $CLI volumes delete mycatalog.myschema.myname
3+
trace $CLI bundle plan
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
RecordRequests = false

acceptance/bundle/resources/volumes/change-name/out.plan.direct-exp.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
"name": {
1717
"action": "update_id"
1818
}
19+
},
20+
"remote": {
21+
"storage_location": {
22+
"action": "skip",
23+
"reason": "remote_only"
24+
}
1925
}
2026
}
2127
}

bundle/direct/bundle_plan.go

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/databricks/cli/libs/structs/structvar"
2222
"github.com/databricks/cli/libs/utils"
2323
"github.com/databricks/databricks-sdk-go"
24+
"github.com/databricks/databricks-sdk-go/apierr"
2425
)
2526

2627
var errDelayed = errors.New("must be resolved after apply")
@@ -169,22 +170,34 @@ func (b *DeploymentBundle) CalculatePlanForDeploy(ctx context.Context, client *d
169170

170171
remoteState, err := adapter.DoRefresh(ctx, dbentry.ID)
171172
if err != nil {
172-
logdiag.LogError(ctx, fmt.Errorf("%s: failed to read id=%q: %w", errorPrefix, dbentry.ID, err))
173-
return false
173+
if errors.Is(err, apierr.ErrResourceDoesNotExist) || errors.Is(err, apierr.ErrNotFound) {
174+
remoteState = nil
175+
} else {
176+
logdiag.LogError(ctx, fmt.Errorf("%s: failed to read id=%q: %w (localAction=%q)", errorPrefix, dbentry.ID, err, localAction.String()))
177+
return false
178+
}
174179
}
175180

176-
remoteStateComparable, err := adapter.RemapState(remoteState)
177-
if err != nil {
178-
logdiag.LogError(ctx, fmt.Errorf("%s: failed to interpret remote state id=%q: %w", errorPrefix, dbentry.ID, err))
179-
}
181+
var remoteAction deployplan.ActionType
182+
var remoteChangeMap map[string]deployplan.Trigger
180183

181-
remoteDiff, err := structdiff.GetStructDiff(remoteStateComparable, entry.NewState.Config)
182-
if err != nil {
183-
logdiag.LogError(ctx, fmt.Errorf("%s: diffing remote state: %w", errorPrefix, err))
184-
return false
184+
if remoteState == nil {
185+
remoteAction = deployplan.ActionTypeCreate
186+
} else {
187+
remoteStateComparable, err := adapter.RemapState(remoteState)
188+
if err != nil {
189+
logdiag.LogError(ctx, fmt.Errorf("%s: failed to interpret remote state id=%q: %w", errorPrefix, dbentry.ID, err))
190+
}
191+
192+
remoteDiff, err := structdiff.GetStructDiff(savedState, remoteStateComparable)
193+
if err != nil {
194+
logdiag.LogError(ctx, fmt.Errorf("%s: diffing remote state: %w", errorPrefix, err))
195+
return false
196+
}
197+
198+
remoteAction, remoteChangeMap = interpretOldStateVsRemoteState(adapter, remoteDiff)
185199
}
186200

187-
remoteAction, remoteChangeMap := convertChangesToTriggersMap(adapter, remoteDiff)
188201
entry.Action = max(localAction, remoteAction).String()
189202

190203
if len(localChangeMap) > 0 || len(remoteChangeMap) > 0 {
@@ -250,6 +263,68 @@ func convertChangesToTriggersMap(adapter *dresources.Adapter, diff []structdiff.
250263
return action, m
251264
}
252265

266+
/*
267+
268+
How we interpret remote and local differences, few examples:
269+
270+
previous state: x
271+
new state : y
272+
remote state: z
273+
274+
previous state: x
275+
new state: y
276+
remote state: x
277+
278+
remote-value is the same as last deployed, this is the default and not interesting, so it won’t be included in Changes.Remote
279+
280+
281+
diff(savedState, remoteValue) —> no changes there, not interesting
282+
283+
284+
previous state: x
285+
new state: y
286+
remote state: y
287+
288+
remote-value is different from last-deployed. One can say that because new-config and remote-value are converged on the same value, this should be noop/skip, but we’ve chosen to always act on local config changes, to avoid surprises.
289+
290+
291+
To summarize, Remote.Changes is diff between previous state and remote state. If there are both local and remote actions, we take maximum possible action.
292+
293+
294+
previous state: nil
295+
new state: <irrelevant>
296+
remote state: z
297+
298+
This is a case of server-side default being set. We’ll include it into Changes.Remote with action="skip” and reason="server_side_only”
299+
*/
300+
301+
func interpretOldStateVsRemoteState(adapter *dresources.Adapter, diff []structdiff.Change) (deployplan.ActionType, map[string]deployplan.Trigger) {
302+
action := deployplan.ActionTypeSkip
303+
m := make(map[string]deployplan.Trigger)
304+
305+
for _, ch := range diff {
306+
if ch.Old == nil {
307+
m[ch.Path.String()] = deployplan.Trigger{
308+
Action: deployplan.ActionTypeSkipString,
309+
// a.k.a server-side default
310+
Reason: "remote_only",
311+
}
312+
continue
313+
}
314+
fieldAction := adapter.ClassifyByTriggers(ch)
315+
if fieldAction > action {
316+
action = fieldAction
317+
}
318+
m[ch.Path.String()] = deployplan.Trigger{Action: fieldAction.String()}
319+
}
320+
321+
if len(m) == 0 {
322+
m = nil
323+
}
324+
325+
return action, m
326+
}
327+
253328
func (b *DeploymentBundle) CalculatePlanForDestroy(ctx context.Context, client *databricks.WorkspaceClient) (*deployplan.Plan, error) {
254329
b.StateDB.AssertOpened()
255330

bundle/direct/dresources/pipeline.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ func (*ResourcePipeline) RemapState(p *pipelines.GetPipelineResponse) *pipelines
4242
EventLog: spec.EventLog,
4343
Filters: spec.Filters,
4444
GatewayDefinition: spec.GatewayDefinition,
45-
Id: spec.Id,
45+
// Clear "id" field, otherwise it shows up in changes.remote
46+
Id: "",
4647
IngestionDefinition: spec.IngestionDefinition,
4748
Libraries: spec.Libraries,
4849
Name: spec.Name,
@@ -57,7 +58,7 @@ func (*ResourcePipeline) RemapState(p *pipelines.GetPipelineResponse) *pipelines
5758
Tags: spec.Tags,
5859
Target: spec.Target,
5960
Trigger: spec.Trigger,
60-
ForceSendFields: filterFields[pipelines.CreatePipeline](spec.ForceSendFields, "AllowDuplicateNames", "DryRun", "RunAs"),
61+
ForceSendFields: filterFields[pipelines.CreatePipeline](spec.ForceSendFields, "AllowDuplicateNames", "DryRun", "RunAs", "Id"),
6162
}
6263
}
6364

0 commit comments

Comments
 (0)