Skip to content

Commit 447c051

Browse files
Merge branch 'master' into DOCS-147-link-to-docs
2 parents cff4e36 + 10a85a1 commit 447c051

12 files changed

+256
-30
lines changed

.github/workflows/acceptance-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424

2525
- name: Run tests
2626
run: |
27-
TF_ACC=1 go test -v ./... -parallel=32 -timeout=30m
27+
TF_ACC=1 go test -v ./... -parallel=6 -timeout=30m
2828
env:
2929
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
3030
CLOUDSMITH_NAMESPACE: terraform-provider-testing

cloudsmith/resource_entitlement_control.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,33 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"time"
78

89
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
910
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1011
)
1112

13+
// waitForEntitlementControlEnabledResource polls until the entitlement token's enabled state matches wantEnabled or times out.
14+
func waitForEntitlementControlEnabledResource(pc *providerConfig, namespace, repository, identifier string, wantEnabled bool, timeoutSec int) error {
15+
deadline := time.Now().Add(time.Duration(timeoutSec) * time.Second)
16+
for {
17+
req := pc.APIClient.EntitlementsApi.EntitlementsRead(pc.Auth, namespace, repository, identifier)
18+
entitlement, resp, err := pc.APIClient.EntitlementsApi.EntitlementsReadExecute(req)
19+
if resp != nil {
20+
defer resp.Body.Close()
21+
}
22+
if err == nil {
23+
if entitlement.GetIsActive() == wantEnabled {
24+
return nil
25+
}
26+
}
27+
if time.Now().After(deadline) {
28+
return fmt.Errorf("timeout waiting for entitlement control enabled=%v", wantEnabled)
29+
}
30+
time.Sleep(1 * time.Second)
31+
}
32+
}
33+
1234
func entitlementControlImport(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
1335
idParts := strings.Split(d.Id(), ".")
1436
if len(idParts) != 3 {
@@ -46,6 +68,9 @@ func entitlementControlCreate(d *schema.ResourceData, m interface{}) error {
4668
}
4769

4870
d.SetId(identifier)
71+
if err := waitForEntitlementControlEnabledResource(pc, namespace, repository, identifier, enabled, 15); err != nil {
72+
return err
73+
}
4974
return entitlementControlRead(d, m)
5075
}
5176

@@ -89,7 +114,10 @@ func entitlementControlUpdate(d *schema.ResourceData, m interface{}) error {
89114
return err
90115
}
91116
}
92-
117+
// Wait for the entitlement to reach the desired state
118+
if err := waitForEntitlementControlEnabledResource(pc, namespace, repository, d.Id(), enabled, 30); err != nil {
119+
return err
120+
}
93121
return entitlementControlRead(d, m)
94122
}
95123

@@ -104,7 +132,10 @@ func entitlementControlDelete(d *schema.ResourceData, m interface{}) error {
104132
if err != nil {
105133
return err
106134
}
107-
135+
// Wait for the entitlement to be disabled
136+
if err := waitForEntitlementControlEnabledResource(pc, namespace, repository, d.Id(), false, 30); err != nil {
137+
return err
138+
}
108139
return nil
109140
}
110141

cloudsmith/resource_entitlement_control_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"os"
77
"testing"
8+
"time"
89

910
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
@@ -27,6 +28,20 @@ func TestAccEntitlementControl_basic(t *testing.T) {
2728
Config: testAccEntitlementControlConfigBasic,
2829
Check: resource.ComposeTestCheckFunc(
2930
testAccEntitlementControlCheckExists("cloudsmith_entitlement_control.test"),
31+
func(s *terraform.State) error {
32+
resourceState, ok := s.RootModule().Resources["cloudsmith_entitlement_control.test"]
33+
if !ok {
34+
return fmt.Errorf("resource not found: %s", "cloudsmith_entitlement_control.test")
35+
}
36+
if resourceState.Primary.ID == "" {
37+
return fmt.Errorf("resource id not set")
38+
}
39+
pc := testAccProvider.Meta().(*providerConfig)
40+
namespace := os.Getenv("CLOUDSMITH_NAMESPACE")
41+
repository := resourceState.Primary.Attributes["repository"]
42+
identifier := resourceState.Primary.ID
43+
return waitForEntitlementControlEnabled(pc, namespace, repository, identifier, true, 15)
44+
},
3045
resource.TestCheckResourceAttr("cloudsmith_entitlement_control.test", "namespace", os.Getenv("CLOUDSMITH_NAMESPACE")),
3146
resource.TestCheckResourceAttr("cloudsmith_entitlement_control.test", "enabled", "true"),
3247
),
@@ -35,6 +50,20 @@ func TestAccEntitlementControl_basic(t *testing.T) {
3550
Config: testAccEntitlementControlConfigBasicUpdate,
3651
Check: resource.ComposeTestCheckFunc(
3752
testAccEntitlementControlCheckExists("cloudsmith_entitlement_control.test"),
53+
func(s *terraform.State) error {
54+
resourceState, ok := s.RootModule().Resources["cloudsmith_entitlement_control.test"]
55+
if !ok {
56+
return fmt.Errorf("resource not found: %s", "cloudsmith_entitlement_control.test")
57+
}
58+
if resourceState.Primary.ID == "" {
59+
return fmt.Errorf("resource id not set")
60+
}
61+
pc := testAccProvider.Meta().(*providerConfig)
62+
namespace := os.Getenv("CLOUDSMITH_NAMESPACE")
63+
repository := resourceState.Primary.Attributes["repository"]
64+
identifier := resourceState.Primary.ID
65+
return waitForEntitlementControlEnabled(pc, namespace, repository, identifier, false, 15)
66+
},
3867
resource.TestCheckResourceAttr("cloudsmith_entitlement_control.test", "namespace", os.Getenv("CLOUDSMITH_NAMESPACE")),
3968
resource.TestCheckResourceAttr("cloudsmith_entitlement_control.test", "enabled", "false"),
4069
),
@@ -120,6 +149,28 @@ func testAccEntitlementControlCheckExists(resourceName string) resource.TestChec
120149
}
121150
}
122151

152+
func waitForEntitlementControlEnabled(pc *providerConfig, namespace, repository, identifier string, wantEnabled bool, timeoutSec int) error {
153+
deadline := time.Now().Add(time.Duration(timeoutSec) * time.Second)
154+
for {
155+
req := pc.APIClient.EntitlementsApi.EntitlementsRead(pc.Auth, namespace, repository, identifier)
156+
entitlement, resp, err := pc.APIClient.EntitlementsApi.EntitlementsReadExecute(req)
157+
if resp != nil {
158+
defer resp.Body.Close()
159+
}
160+
if err == nil {
161+
if entitlement.GetIsActive() == wantEnabled {
162+
return nil
163+
}
164+
} else if is404(resp) {
165+
return fmt.Errorf("entitlement not found while waiting for enabled=%v", wantEnabled)
166+
}
167+
if time.Now().After(deadline) {
168+
return fmt.Errorf("timeout waiting for entitlement control enabled=%v", wantEnabled)
169+
}
170+
time.Sleep(1 * time.Second)
171+
}
172+
}
173+
123174
var testAccEntitlementControlConfigBasic = fmt.Sprintf(`
124175
resource "cloudsmith_repository" "test" {
125176
name = "terraform-acc-test-ent-ctrl"

cloudsmith/resource_package_deny_policy_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestAccPackageDenyPolicy_basic(t *testing.T) {
2727
resource.TestCheckResourceAttr("cloudsmith_package_deny_policy.test", "namespace", os.Getenv("CLOUDSMITH_NAMESPACE")),
2828
resource.TestCheckResourceAttr("cloudsmith_package_deny_policy.test", "enabled", "true"),
2929
resource.TestCheckResourceAttr("cloudsmith_package_deny_policy.test", "name", "test-package-deny-policy-terraform-provider"),
30-
resource.TestCheckResourceAttr("cloudsmith_package_deny_policy.test", "package_query", "name:example"),
30+
resource.TestCheckResourceAttr("cloudsmith_package_deny_policy.test", "package_query", "name:example_new"),
3131
),
3232
},
3333
},
@@ -41,7 +41,7 @@ resource "cloudsmith_package_deny_policy" "test" {
4141
namespace = "%s"
4242
enabled = true
4343
name = "test-package-deny-policy-terraform-provider"
44-
package_query = "name:example"
44+
package_query = "name:example_new"
4545
}
4646
`, os.Getenv("CLOUDSMITH_NAMESPACE"))
4747

cloudsmith/resource_repository_retention_rule.go

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@ func resourceRepoRetentionRuleUpdate(d *schema.ResourceData, meta interface{}) e
2626
namespace := requiredString(d, "namespace")
2727
repo := requiredString(d, "repository")
2828

29-
// Check if the operation is a delete operation
30-
isDelete := !d.Get("retention_enabled").(bool)
31-
3229
req := pc.APIClient.ReposApi.RepoRetentionPartialUpdate(pc.Auth, namespace, repo)
3330
updateData := cloudsmith.RepositoryRetentionRulesRequestPatch{
3431
RetentionEnabled: optionalBool(d, "retention_enabled"),
3532
RetentionGroupByName: optionalBool(d, "retention_group_by_name"),
3633
RetentionGroupByFormat: optionalBool(d, "retention_group_by_format"),
3734
RetentionGroupByPackageType: optionalBool(d, "retention_group_by_package_type"),
35+
RetentionPackageQueryString: nullableString(d, "retention_package_query_string"),
3836
}
3937

4038
// Explicitly set these values, even if they're zero
@@ -53,13 +51,6 @@ func resourceRepoRetentionRuleUpdate(d *schema.ResourceData, meta interface{}) e
5351

5452
req = req.Data(updateData)
5553

56-
// If it's a delete operation, disable the retention rule
57-
if isDelete {
58-
req = req.Data(cloudsmith.RepositoryRetentionRulesRequestPatch{
59-
RetentionEnabled: cloudsmith.PtrBool(false),
60-
})
61-
}
62-
6354
// Execute the request
6455
_, httpResp, err := req.Execute()
6556
if err != nil {
@@ -101,27 +92,59 @@ func resourceRepoRetentionRuleRead(d *schema.ResourceData, meta interface{}) err
10192
}
10293
}
10394

104-
// Handle the response
10595
d.Set("retention_count_limit", resp.RetentionCountLimit)
10696
d.Set("retention_days_limit", resp.RetentionDaysLimit)
10797
d.Set("retention_enabled", resp.RetentionEnabled)
10898
d.Set("retention_group_by_name", resp.RetentionGroupByName)
10999
d.Set("retention_group_by_format", resp.RetentionGroupByFormat)
110100
d.Set("retention_group_by_package_type", resp.RetentionGroupByPackageType)
111101
d.Set("retention_size_limit", resp.RetentionSizeLimit)
112-
113-
d.Set("namespace", namespace)
102+
if resp.RetentionPackageQueryString.IsSet() && resp.RetentionPackageQueryString.Get() != nil {
103+
d.Set("retention_package_query_string", *resp.RetentionPackageQueryString.Get())
104+
} else {
105+
d.Set("retention_package_query_string", "")
106+
}
114107
d.SetId(fmt.Sprintf("%s.%s", namespace, repo))
115108

116109
return nil
117110
}
118111

112+
func resourceRepoRetentionRuleDelete(d *schema.ResourceData, meta interface{}) error {
113+
pc := meta.(*providerConfig)
114+
115+
namespace := requiredString(d, "namespace")
116+
repo := requiredString(d, "repository")
117+
118+
req := pc.APIClient.ReposApi.RepoRetentionPartialUpdate(pc.Auth, namespace, repo)
119+
updateData := cloudsmith.RepositoryRetentionRulesRequestPatch{
120+
RetentionEnabled: cloudsmith.PtrBool(false),
121+
}
122+
req = req.Data(updateData)
123+
124+
_, httpResp, err := req.Execute()
125+
if err != nil {
126+
switch httpResp.StatusCode {
127+
case 400:
128+
return fmt.Errorf("request could not be processed: %s", err)
129+
case 404:
130+
return nil
131+
case 422:
132+
return fmt.Errorf("missing or invalid parameters: %s", err)
133+
default:
134+
return fmt.Errorf("error disabling repository retention rule: %s", err)
135+
}
136+
}
137+
138+
d.SetId("")
139+
return nil
140+
}
141+
119142
func resourceRepoRetentionRule() *schema.Resource {
120143
return &schema.Resource{
121144
Create: resourceRepoRetentionRuleUpdate,
122145
Read: resourceRepoRetentionRuleRead,
123146
Update: resourceRepoRetentionRuleUpdate,
124-
Delete: resourceRepoRetentionRuleUpdate,
147+
Delete: resourceRepoRetentionRuleDelete,
125148
Importer: &schema.ResourceImporter{
126149
State: importRepoRetentionRule,
127150
},
@@ -182,6 +205,11 @@ func resourceRepoRetentionRule() *schema.Resource {
182205
Optional: true,
183206
Description: "The maximum total size (in bytes) of packages to retain. Must be between 0 and 21474836480 (21.47 GB / 21474.83 MB).",
184207
},
208+
"retention_package_query_string": {
209+
Type: schema.TypeString,
210+
Optional: true,
211+
Description: "A package search expression which, if provided, filters the packages to be deleted.",
212+
},
185213
},
186214
}
187215
}

cloudsmith/resource_repository_retention_rule_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func TestAccRepositoryRetentionRule_basic(t *testing.T) {
3333
resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_group_by_format", "false"),
3434
resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_group_by_package_type", "false"),
3535
resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_size_limit", "0"),
36+
resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_package_query_string", "name:test"),
3637
),
3738
},
3839
},
@@ -63,5 +64,6 @@ resource "cloudsmith_repository_retention_rule" "test" {
6364
retention_group_by_format = false
6465
retention_group_by_package_type = false
6566
retention_size_limit = 0
67+
retention_package_query_string = "name:test"
6668
}
6769
`, os.Getenv("CLOUDSMITH_NAMESPACE"), os.Getenv("CLOUDSMITH_NAMESPACE"))

cloudsmith/resource_repository_upstream_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ resource "cloudsmith_repository_upstream" "ubuntu" {
177177
{
178178
Config: testAccRepositoryDebUpstreamConfigBasic,
179179
Check: resource.ComposeTestCheckFunc(
180+
waitForIsActiveTrue(debUpstreamResourceName),
180181
resource.TestCheckResourceAttr(debUpstreamResourceName, AuthMode, "None"),
181182
resource.TestCheckResourceAttr(debUpstreamResourceName, AuthUsername, ""),
182183
resource.TestCheckResourceAttrSet(debUpstreamResourceName, Component),
@@ -1375,3 +1376,28 @@ func testAccRepositoryUpstreamCheckDestroy(resourceName string) resource.TestChe
13751376
return nil
13761377
}
13771378
}
1379+
1380+
// waitForIsActiveTrue waits up to 4 minutes for the resource's is_active attribute to become "true", checking every 10 seconds.
1381+
func waitForIsActiveTrue(resourceName string) resource.TestCheckFunc {
1382+
return func(s *terraform.State) error {
1383+
const (
1384+
maxWait = 4 * time.Minute
1385+
interval = 10 * time.Second
1386+
)
1387+
start := time.Now()
1388+
for {
1389+
resourceState, ok := s.RootModule().Resources[resourceName]
1390+
if !ok {
1391+
return fmt.Errorf("resource %s not found in state", resourceName)
1392+
}
1393+
isActive := resourceState.Primary.Attributes[IsActive]
1394+
if isActive == "true" {
1395+
return nil
1396+
}
1397+
if time.Since(start) > maxWait {
1398+
return fmt.Errorf("timed out waiting for %s is_active to become true", resourceName)
1399+
}
1400+
time.Sleep(interval)
1401+
}
1402+
}
1403+
}

0 commit comments

Comments
 (0)