-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add safe-delete workspace API, and org setting to restrict force-delete #539
Changes from 1 commit
7e7faed
8730b72
51341b4
16d153b
2213c1e
e8b91ef
01e5267
dc48cae
d86cb66
f3a30d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…e admins can force delete
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -565,7 +565,41 @@ func TestOrganizationsReadRunTasksEntitlement(t *testing.T) { | |
assert.NotEmpty(t, entitlements.ID) | ||
assert.True(t, entitlements.RunTasks) | ||
}) | ||
} | ||
|
||
func TestOrganizationsAllowForceDeleteSetting(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our docs should be much more explicit, but we've recently introduced test splitting in our CI and we're requiring all top-level tests to call |
||
client := testClient(t) | ||
ctx := context.Background() | ||
|
||
t.Run("creates and updates allow force delete", func(t *testing.T) { | ||
options := OrganizationCreateOptions{ | ||
Name: String(randomString(t)), | ||
Email: String(randomString(t) + "@tfe.local"), | ||
AllowForceDeleteWorkspaces: Bool(true), | ||
} | ||
|
||
org, err := client.Organizations.Create(ctx, options) | ||
assert.Nil(t, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be |
||
|
||
t.Cleanup(func() { | ||
err := client.Organizations.Delete(ctx, org.Name) | ||
if err != nil { | ||
t.Logf("error deleting organization (%s): %s", org.Name, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally we |
||
} | ||
}) | ||
|
||
assert.Equal(t, *options.Name, org.Name) | ||
assert.Equal(t, *options.Email, org.Email) | ||
assert.True(t, org.AllowForceDeleteWorkspaces) | ||
|
||
org, err = client.Organizations.Update(ctx, org.Name, OrganizationUpdateOptions{AllowForceDeleteWorkspaces: Bool(false)}) | ||
assert.Nil(t, err) | ||
assert.False(t, org.AllowForceDeleteWorkspaces) | ||
|
||
org, err = client.Organizations.Read(ctx, org.Name) | ||
assert.Nil(t, err) | ||
assert.False(t, org.AllowForceDeleteWorkspaces) | ||
}) | ||
} | ||
|
||
func orgItemsContainsName(items []*Organization, name string) bool { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1211,6 +1211,126 @@ func TestWorkspacesDeleteByID(t *testing.T) { | |
}) | ||
} | ||
|
||
func TestCanForceDeletePermission(t *testing.T) { | ||
client := testClient(t) | ||
ctx := context.Background() | ||
|
||
orgTest, orgTestCleanup := createOrganization(t, client) | ||
defer orgTestCleanup() | ||
|
||
wTest, _ := createWorkspace(t, client, orgTest) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, Is there a reason we don't clean this workspace up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I was copying from the update tests in this file, which also ignore the cleanup Im not sure why though...I will try to update all the tests to do the cleanup There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I remember. Because the the workspace gets removed in the process of the test, and then the cleanup call throws an errors. Or, in some other tests (and also this one, I would guess) the org also gets cleaned up first, which deletes the workspace and causes a defered workspace cleanup to fail E.g. if you try to defer the cleanup in the test I linked above you get
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That feels like it should be a solve-able problem. I will update the workspace cleanup function not to error on 404s, and then update the other tests in this file to cleanup the workspaces which they create |
||
|
||
t.Run("workspace permission set includes can-force-delete", func(t *testing.T) { | ||
w, err := client.Workspaces.ReadByID(ctx, wTest.ID) | ||
require.NoError(t, err) | ||
assert.Equal(t, wTest, w) | ||
assert.Equal(t, wTest, w) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. duplicate assertion here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch, thanks! |
||
assert.NotNil(t, w.Permissions.CanForceDelete) | ||
assert.True(t, *w.Permissions.CanForceDelete) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like your test is panicking:
Two things:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think that this is at least partially it...where can I find the instance that the acceptance tests run against? I can check out if it has all the api changes expected Edit: Found it, and it looks like it has at least some of the expected changes...I will dig into why the tests are failing like this! Edit edit: I was wrong in the previous edit. I was looking at |
||
}) | ||
} | ||
|
||
func TestWorkspacesSafeDelete(t *testing.T) { | ||
client := testClient(t) | ||
ctx := context.Background() | ||
|
||
orgTest, orgTestCleanup := createOrganization(t, client) | ||
defer orgTestCleanup() | ||
|
||
wTest, _ := createWorkspace(t, client, orgTest) | ||
|
||
t.Run("with valid options", func(t *testing.T) { | ||
err := client.Workspaces.SafeDelete(ctx, orgTest.Name, wTest.Name) | ||
require.NoError(t, err) | ||
|
||
// Try loading the workspace - it should fail. | ||
_, err = client.Workspaces.Read(ctx, orgTest.Name, wTest.Name) | ||
assert.Equal(t, ErrResourceNotFound, err) | ||
}) | ||
|
||
t.Run("when organization is invalid", func(t *testing.T) { | ||
err := client.Workspaces.SafeDelete(ctx, badIdentifier, wTest.Name) | ||
assert.EqualError(t, err, ErrInvalidOrg.Error()) | ||
}) | ||
|
||
t.Run("when workspace is invalid", func(t *testing.T) { | ||
err := client.Workspaces.SafeDelete(ctx, orgTest.Name, badIdentifier) | ||
assert.EqualError(t, err, ErrInvalidWorkspaceValue.Error()) | ||
}) | ||
|
||
t.Run("when workspace is locked", func(t *testing.T) { | ||
wTest, workspaceCleanup := createWorkspace(t, client, orgTest) | ||
defer workspaceCleanup() | ||
w, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{}) | ||
assert.NoError(t, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missed one |
||
assert.True(t, w.Locked) | ||
|
||
err = client.Workspaces.SafeDelete(ctx, orgTest.Name, wTest.Name) | ||
assert.Contains(t, err.Error(), "conflict") | ||
assert.Contains(t, err.Error(), "currently locked") | ||
}) | ||
|
||
t.Run("when workspace has resources under management", func(t *testing.T) { | ||
wTest, workspaceCleanup := createWorkspace(t, client, orgTest) | ||
defer workspaceCleanup() | ||
_, svTestCleanup := createStateVersion(t, client, 0, wTest) | ||
t.Cleanup(svTestCleanup) | ||
|
||
err := client.Workspaces.SafeDelete(ctx, orgTest.Name, wTest.Name) | ||
// cant verify the exact error here because it is timing dependent on the backend | ||
// based on whether the state version has been processed yet | ||
assert.Contains(t, err.Error(), "conflict") | ||
}) | ||
} | ||
|
||
func TestWorkspacesSafeDeleteByID(t *testing.T) { | ||
client := testClient(t) | ||
ctx := context.Background() | ||
|
||
orgTest, orgTestCleanup := createOrganization(t, client) | ||
defer orgTestCleanup() | ||
|
||
wTest, _ := createWorkspace(t, client, orgTest) | ||
|
||
t.Run("with valid options", func(t *testing.T) { | ||
err := client.Workspaces.SafeDeleteByID(ctx, wTest.ID) | ||
require.NoError(t, err) | ||
|
||
// Try loading the workspace - it should fail. | ||
_, err = client.Workspaces.ReadByID(ctx, wTest.ID) | ||
assert.Equal(t, ErrResourceNotFound, err) | ||
}) | ||
|
||
t.Run("without a valid workspace ID", func(t *testing.T) { | ||
err := client.Workspaces.SafeDeleteByID(ctx, badIdentifier) | ||
assert.EqualError(t, err, ErrInvalidWorkspaceID.Error()) | ||
}) | ||
|
||
t.Run("when workspace is locked", func(t *testing.T) { | ||
wTest, workspaceCleanup := createWorkspace(t, client, orgTest) | ||
defer workspaceCleanup() | ||
w, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{}) | ||
assert.NoError(t, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
assert.True(t, w.Locked) | ||
|
||
err = client.Workspaces.SafeDeleteByID(ctx, wTest.ID) | ||
assert.Contains(t, err.Error(), "conflict") | ||
assert.Contains(t, err.Error(), "currently locked") | ||
}) | ||
|
||
t.Run("when workspace has resources under management", func(t *testing.T) { | ||
wTest, workspaceCleanup := createWorkspace(t, client, orgTest) | ||
defer workspaceCleanup() | ||
_, svTestCleanup := createStateVersion(t, client, 0, wTest) | ||
t.Cleanup(svTestCleanup) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non-blocker: Not a huge deal to mix the two, but the preference here is for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean that it is preferred to do |
||
|
||
err := client.Workspaces.SafeDeleteByID(ctx, wTest.ID) | ||
// cant verify the exact error here because it is timing dependent on the backend | ||
// based on whether the state version has been processed yet | ||
assert.Contains(t, err.Error(), "conflict") | ||
}) | ||
} | ||
|
||
func TestWorkspacesRemoveVCSConnection(t *testing.T) { | ||
skipIfNotCINode(t) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this property is missing for older TFE versions, the default will be false. And then, of course, all deletes will be force deletes because safe delete isn't implemented. I think we are OK with this contradiction but I wanted to point it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a really good point...I am also ok with the contradiction, it seems less confusing than making this a
*bool
or something when it isn't strictly necessary and we use regularbool
s are used for everything else in this struct. I also cant think of a less confusing name...I will add a comment though to make it clear that this will be false for older TFE versions, even though all deletes are force deletes in that case