Skip to content

Commit

Permalink
Rewrite DeletedWith properties when renaming stacks (#16216)
Browse files Browse the repository at this point in the history
When renaming a stack, we need to rewrite URN references to use the new
stack name instead of the old one. Presently such references can occur
as:

* `Parent` references
* `Provider` references
* `Dependencies`
* `PropertyDependencies`
* `DeletedWith` references

The current renaming implementation fails to rewrite `DeletedWith`
references. Previously this went unnoticed since such references were
also omitted when checking snapshot integrity. Now that integrity checks
correctly inspect `DeletedWith` properties, the omission during rename
has been surfaced. This commit fixes renaming to handle `DeletedWith`
correctly. A follow-up should also ensure that renaming checks integrity
itself prior to operation completion.

Fixes #16215
  • Loading branch information
lunaris committed May 16, 2024
1 parent ab7acdb commit 41b967d
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- type: fix
scope: backend/diy
description: Rewrite DeletedWith references when renaming stacks
103 changes: 103 additions & 0 deletions pkg/backend/diy/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,109 @@ func TestRenameWorks(t *testing.T) {
assert.Equal(t, apitype.DestroyUpdate, history[0].Kind)
}

func TestRenamePreservesIntegrity(t *testing.T) {
t.Parallel()

// Arrange.
tmpDir := t.TempDir()
ctx := context.Background()
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
assert.NoError(t, err)

stackRef, err := b.ParseStackReference("organization/project/a")
assert.NoError(t, err)
stk, err := b.CreateStack(ctx, stackRef, "", nil)
assert.NoError(t, err)
assert.NotNil(t, stk)

rBase := &resource.State{
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "base"),
Type: "a:b:c",
Inputs: resource.PropertyMap{
resource.PropertyKey("p"): resource.NewStringProperty("v"),
},
}

rDependency := &resource.State{
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "dependency"),
Type: "a:b:c",
Inputs: resource.PropertyMap{
resource.PropertyKey("p"): resource.NewStringProperty("v"),
},
Dependencies: []resource.URN{rBase.URN},
}

rPropertyDependency := &resource.State{
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "property-dependency"),
Type: "a:b:c",
Inputs: resource.PropertyMap{
resource.PropertyKey("p"): resource.NewStringProperty("v"),
},
PropertyDependencies: map[resource.PropertyKey][]resource.URN{
resource.PropertyKey("p"): {rBase.URN},
},
}

rDeletedWith := &resource.State{
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "deleted-with"),
Type: "a:b:c",
Inputs: resource.PropertyMap{
resource.PropertyKey("p"): resource.NewStringProperty("v"),
},
DeletedWith: rBase.URN,
}

rParent := &resource.State{
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "parent"),
Type: "a:b:c",
Inputs: resource.PropertyMap{
resource.PropertyKey("p"): resource.NewStringProperty("v"),
},
Parent: rBase.URN,
}

resources := []*resource.State{
rBase,
rDependency,
rPropertyDependency,
rDeletedWith,
rParent,
}

snap := deploy.NewSnapshot(deploy.Manifest{}, nil, resources, nil)
ctx = context.Background()

sdep, err := stack.SerializeDeployment(ctx, snap, false)
assert.NoError(t, err)

data, err := encoding.JSON.Marshal(sdep)
assert.NoError(t, err)

err = b.ImportDeployment(ctx, stk, &apitype.UntypedDeployment{
Version: 3,
Deployment: json.RawMessage(data),
})
assert.NoError(t, err)

err = snap.VerifyIntegrity()
assert.NoError(t, err)

// Act.
renamedStackRef, err := b.RenameStack(ctx, stk, "organization/project/a-renamed")
assert.NoError(t, err)

// Assert.
renamedStk, err := b.GetStack(ctx, renamedStackRef)
assert.NoError(t, err)
assert.NotNil(t, renamedStk)

renamedSnap, err := renamedStk.Snapshot(ctx, nil)
assert.NoError(t, err)

err = renamedSnap.VerifyIntegrity()
assert.NoError(t, err)
}

func TestRenameProjectWorks(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions pkg/resource/edit/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ func RenameStack(deployment *apitype.DeploymentV3, newName tokens.StackName, new
}
}

if res.DeletedWith != "" {
res.DeletedWith = rewriteUrn(res.DeletedWith)
}

if res.Provider != "" {
providerRef, err := providers.ParseReference(res.Provider)
contract.AssertNoErrorf(err, "failed to parse provider reference from validated checkpoint")
Expand Down

0 comments on commit 41b967d

Please sign in to comment.