Skip to content

Commit b3769d2

Browse files
committed
Merge branch 'main' into hashimoon/terraform-test-validations
2 parents b9a7941 + a245d58 commit b3769d2

13 files changed

+653
-41
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
# UNRELEASED
2+
<!-- Add CHANGELOG entry to this section for any PR awaiting the next release -->
3+
<!-- Please also include if this is a Bug Fix, Enhancement, or Feature -->
4+
5+
## Features
6+
* New WorkspaceSettingOverwritesOptions field for allowing workspaces to defer some settings to a default from their organization or project by @SwiftEngineer [#762](https://github.com/hashicorp/go-tfe/pull/762)
7+
* Added support for setting a default execution mode and agent pool at the organization level by @SwiftEngineer [#762](https://github.com/hashicorp/go-tfe/pull/762)
28

39
## Features
410
* Removed BETA labels for StateVersion Upload method, ConfigurationVersion `provisional` field, and `save-plan` runs by @brandonc [#800](https://github.com/hashicorp/go-tfe/pull/800)
11+
* Allow soft deleting, restoring, and permanently deleting StateVersion and ConfigurationVersion backing data by @mwudka [#801](https://github.com/hashicorp/go-tfe/pull/801)
512

613
# v.1.38.0
714

configuration_version.go

+38
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ type ConfigurationVersions interface {
5555

5656
// Download a configuration version. Only configuration versions in the uploaded state may be downloaded.
5757
Download(ctx context.Context, cvID string) ([]byte, error)
58+
59+
// SoftDeleteBackingData soft deletes the configuration version's backing data
60+
// **Note: This functionality is only available in Terraform Enterprise.**
61+
SoftDeleteBackingData(ctx context.Context, svID string) error
62+
63+
// RestoreBackingData restores a soft deleted configuration version's backing data
64+
// **Note: This functionality is only available in Terraform Enterprise.**
65+
RestoreBackingData(ctx context.Context, svID string) error
66+
67+
// PermanentlyDeleteBackingData permanently deletes a soft deleted configuration version's backing data
68+
// **Note: This functionality is only available in Terraform Enterprise.**
69+
PermanentlyDeleteBackingData(ctx context.Context, svID string) error
5870
}
5971

6072
// configurationVersions implements ConfigurationVersions.
@@ -356,3 +368,29 @@ func (s *configurationVersions) Download(ctx context.Context, cvID string) ([]by
356368

357369
return buf.Bytes(), nil
358370
}
371+
372+
func (s *configurationVersions) SoftDeleteBackingData(ctx context.Context, cvID string) error {
373+
return s.manageBackingData(ctx, cvID, "soft_delete_backing_data")
374+
}
375+
376+
func (s *configurationVersions) RestoreBackingData(ctx context.Context, cvID string) error {
377+
return s.manageBackingData(ctx, cvID, "restore_backing_data")
378+
}
379+
380+
func (s *configurationVersions) PermanentlyDeleteBackingData(ctx context.Context, cvID string) error {
381+
return s.manageBackingData(ctx, cvID, "permanently_delete_backing_data")
382+
}
383+
384+
func (s *configurationVersions) manageBackingData(ctx context.Context, cvID, action string) error {
385+
if !validStringID(&cvID) {
386+
return ErrInvalidConfigVersionID
387+
}
388+
389+
u := fmt.Sprintf("configuration-versions/%s/actions/%s", cvID, action)
390+
req, err := s.client.NewRequest("POST", u, nil)
391+
if err != nil {
392+
return err
393+
}
394+
395+
return req.Do(ctx, nil)
396+
}

configuration_version_integration_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,49 @@ func TestConfigurationVersions_Unmarshal(t *testing.T) {
472472
assert.Equal(t, cv.Provisional, true)
473473
assert.Equal(t, cv.Speculative, true)
474474
}
475+
476+
func TestConfigurationVersions_ManageBackingData(t *testing.T) {
477+
skipUnlessEnterprise(t)
478+
479+
client := testClient(t)
480+
ctx := context.Background()
481+
482+
workspace, workspaceCleanup := createWorkspace(t, client, nil)
483+
t.Cleanup(workspaceCleanup)
484+
485+
nonCurrentCv, uploadedCvCleanup := createUploadedConfigurationVersion(t, client, workspace)
486+
defer uploadedCvCleanup()
487+
488+
_, uploadedCvCleanup = createUploadedConfigurationVersion(t, client, workspace)
489+
defer uploadedCvCleanup()
490+
491+
t.Run("soft delete backing data", func(t *testing.T) {
492+
err := client.ConfigurationVersions.SoftDeleteBackingData(ctx, nonCurrentCv.ID)
493+
require.NoError(t, err)
494+
495+
_, err = client.ConfigurationVersions.Download(ctx, nonCurrentCv.ID)
496+
assert.Equal(t, ErrResourceNotFound, err)
497+
})
498+
499+
t.Run("restore backing data", func(t *testing.T) {
500+
err := client.ConfigurationVersions.RestoreBackingData(ctx, nonCurrentCv.ID)
501+
require.NoError(t, err)
502+
503+
_, err = client.ConfigurationVersions.Download(ctx, nonCurrentCv.ID)
504+
require.NoError(t, err)
505+
})
506+
507+
t.Run("permanently delete backing data", func(t *testing.T) {
508+
err := client.ConfigurationVersions.SoftDeleteBackingData(ctx, nonCurrentCv.ID)
509+
require.NoError(t, err)
510+
511+
err = client.ConfigurationVersions.PermanentlyDeleteBackingData(ctx, nonCurrentCv.ID)
512+
require.NoError(t, err)
513+
514+
err = client.ConfigurationVersions.RestoreBackingData(ctx, nonCurrentCv.ID)
515+
require.ErrorContainsf(t, err, "transition not allowed", "Restore backing data should fail")
516+
517+
_, err = client.ConfigurationVersions.Download(ctx, nonCurrentCv.ID)
518+
assert.Equal(t, ErrResourceNotFound, err)
519+
})
520+
}

examples/backing_data/main.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package main
5+
6+
import (
7+
"context"
8+
"flag"
9+
"fmt"
10+
tfe "github.com/hashicorp/go-tfe"
11+
"log"
12+
"strings"
13+
)
14+
15+
func main() {
16+
action := flag.String("action", "", "Action (soft-delete|restore|permanently-delete")
17+
externalId := flag.String("external-id", "", "External ID of StateVersion or ConfigurationVersion")
18+
19+
flag.Parse()
20+
21+
if action == nil || *action == "" {
22+
log.Fatal("No Action provided")
23+
}
24+
25+
if externalId == nil || *externalId == "" {
26+
log.Fatal("No external ID provided")
27+
}
28+
29+
ctx := context.Background()
30+
client, err := tfe.NewClient(&tfe.Config{
31+
RetryServerErrors: true,
32+
})
33+
if err != nil {
34+
log.Fatal(err)
35+
}
36+
37+
err = performAction(ctx, client, *action, *externalId)
38+
if err != nil {
39+
log.Fatalf("Error performing action: %v", err)
40+
}
41+
}
42+
43+
func performAction(ctx context.Context, client *tfe.Client, action string, id string) error {
44+
externalIdParts := strings.Split(id, "-")
45+
switch externalIdParts[0] {
46+
case "cv":
47+
switch action {
48+
case "soft-delete":
49+
return client.ConfigurationVersions.SoftDeleteBackingData(ctx, id)
50+
case "restore":
51+
return client.ConfigurationVersions.RestoreBackingData(ctx, id)
52+
case "permanently-delete":
53+
return client.ConfigurationVersions.PermanentlyDeleteBackingData(ctx, id)
54+
default:
55+
return fmt.Errorf("unsupported action: %s", action)
56+
}
57+
case "sv":
58+
switch action {
59+
case "soft-delete":
60+
return client.StateVersions.SoftDeleteBackingData(ctx, id)
61+
case "restore":
62+
return client.StateVersions.RestoreBackingData(ctx, id)
63+
case "permanently-delete":
64+
return client.StateVersions.PermanentlyDeleteBackingData(ctx, id)
65+
default:
66+
return fmt.Errorf("unsupported action: %s", action)
67+
}
68+
default:
69+
return fmt.Errorf("unsupported external ID: %s", id)
70+
}
71+
return nil
72+
}

helper_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,30 @@ func createOrganizationWithOptions(t *testing.T, client *Client, options Organiz
965965
}
966966
}
967967

968+
func createOrganizationWithDefaultAgentPool(t *testing.T, client *Client) (*Organization, func()) {
969+
ctx := context.Background()
970+
org, orgCleanup := createOrganizationWithOptions(t, client, OrganizationCreateOptions{
971+
Name: String("tst-" + randomString(t)),
972+
Email: String(fmt.Sprintf("%[email protected]", randomString(t))),
973+
CostEstimationEnabled: Bool(true),
974+
})
975+
976+
agentPool, _ := createAgentPool(t, client, org)
977+
978+
org, err := client.Organizations.Update(ctx, org.Name, OrganizationUpdateOptions{
979+
DefaultExecutionMode: String("agent"),
980+
DefaultAgentPool: agentPool,
981+
})
982+
983+
if err != nil {
984+
t.Fatal(err)
985+
}
986+
987+
return org, func() {
988+
// delete the org
989+
orgCleanup()
990+
}
991+
}
968992
func createOrganizationMembership(t *testing.T, client *Client, org *Organization) (*OrganizationMembership, func()) {
969993
var orgCleanup func()
970994

mocks/configuration_version_mocks.go

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mocks/state_version_mocks.go

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

organization.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type Organization struct {
7474
CollaboratorAuthPolicy AuthPolicyType `jsonapi:"attr,collaborator-auth-policy"`
7575
CostEstimationEnabled bool `jsonapi:"attr,cost-estimation-enabled"`
7676
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
77+
DefaultExecutionMode string `jsonapi:"attr,default-execution-mode"`
7778
Email string `jsonapi:"attr,email"`
7879
ExternalID string `jsonapi:"attr,external-id"`
7980
OwnersTeamSAMLRoleID string `jsonapi:"attr,owners-team-saml-role-id"`
@@ -90,7 +91,8 @@ type Organization struct {
9091
AllowForceDeleteWorkspaces bool `jsonapi:"attr,allow-force-delete-workspaces"`
9192

9293
// Relations
93-
DefaultProject *Project `jsonapi:"relation,default-project"`
94+
DefaultProject *Project `jsonapi:"relation,default-project"`
95+
DefaultAgentPool *AgentPool `jsonapi:"relation,default-agent-pool"`
9496
}
9597

9698
// OrganizationIncludeOpt represents the available options for include query params.
@@ -198,6 +200,9 @@ type OrganizationCreateOptions struct {
198200

199201
// Optional: AllowForceDeleteWorkspaces toggles behavior of allowing workspace admins to delete workspaces with resources under management.
200202
AllowForceDeleteWorkspaces *bool `jsonapi:"attr,allow-force-delete-workspaces,omitempty"`
203+
204+
// Optional: DefaultExecutionMode the default execution mode for workspaces
205+
DefaultExecutionMode *string `jsonapi:"attr,default-execution-mode,omitempty"`
201206
}
202207

203208
// OrganizationUpdateOptions represents the options for updating an organization.
@@ -237,6 +242,12 @@ type OrganizationUpdateOptions struct {
237242

238243
// Optional: AllowForceDeleteWorkspaces toggles behavior of allowing workspace admins to delete workspaces with resources under management.
239244
AllowForceDeleteWorkspaces *bool `jsonapi:"attr,allow-force-delete-workspaces,omitempty"`
245+
246+
// Optional: DefaultExecutionMode the default execution mode for workspaces
247+
DefaultExecutionMode *string `jsonapi:"attr,default-execution-mode,omitempty"`
248+
249+
// Optional: DefaultAgentPoolId default agent pool for workspaces, requires DefaultExecutionMode to be set to `agent`
250+
DefaultAgentPool *AgentPool `jsonapi:"relation,default-agent-pool,omitempty"`
240251
}
241252

242253
// ReadRunQueueOptions represents the options for showing the queue.

0 commit comments

Comments
 (0)