From 302268cceb6c45006d7b712591cf3b36edc5b87c Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Wed, 12 Apr 2023 17:36:30 +0800 Subject: [PATCH 1/3] feat:support tencentcloud_tcr_tag_retention_rule resource --- tencentcloud/provider.go | 2 + .../resource_tc_tcr_tag_retention_rule.go | 342 ++++++++++++++++++ ...resource_tc_tcr_tag_retention_rule_test.go | 134 +++++++ tencentcloud/service_tencentcloud_tcr.go | 65 ++++ .../r/tcr_tag_retention_rule.html.markdown | 63 ++++ website/tencentcloud.erb | 3 + 6 files changed, 609 insertions(+) create mode 100644 tencentcloud/resource_tc_tcr_tag_retention_rule.go create mode 100644 tencentcloud/resource_tc_tcr_tag_retention_rule_test.go create mode 100644 website/docs/r/tcr_tag_retention_rule.html.markdown diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index f44b5c301e..b3e133c537 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -613,6 +613,7 @@ Tencent Container Registry(TCR) tencentcloud_tcr_repository tencentcloud_tcr_token tencentcloud_tcr_vpc_attachment + tencentcloud_tcr_tag_retention_rule Video on Demand(VOD) Data Source @@ -1661,6 +1662,7 @@ func Provider() terraform.ResourceProvider { "tencentcloud_tcr_repository": resourceTencentCloudTcrRepository(), "tencentcloud_tcr_token": resourceTencentCloudTcrToken(), "tencentcloud_tcr_vpc_attachment": resourceTencentCloudTcrVpcAttachment(), + "tencentcloud_tcr_tag_retention_rule": resourceTencentCloudTcrTagRetentionRule(), "tencentcloud_tdmq_instance": resourceTencentCloudTdmqInstance(), "tencentcloud_tdmq_namespace": resourceTencentCloudTdmqNamespace(), "tencentcloud_tdmq_topic": resourceTencentCloudTdmqTopic(), diff --git a/tencentcloud/resource_tc_tcr_tag_retention_rule.go b/tencentcloud/resource_tc_tcr_tag_retention_rule.go new file mode 100644 index 0000000000..091d19c23c --- /dev/null +++ b/tencentcloud/resource_tc_tcr_tag_retention_rule.go @@ -0,0 +1,342 @@ +/* +Provides a resource to create a tcr tag_retention_rule + +Example Usage + +```hcl +resource "tencentcloud_tcr_namespace" "my_ns" { + instance_id = local.tcr_id + name = "tf_test_ns_retention" + is_public = true + is_auto_scan = true + is_prevent_vul = true + severity = "medium" + cve_whitelist_items { + cve_id = "cve-xxxxx" + } +} + +resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { + registry_id = local.tcr_id + namespace_name = tencentcloud_tcr_namespace.my_ns.name + retention_rule { + key = "nDaysSinceLastPush" + value = 1 + } + cron_setting = "manual" + disabled = false +} +``` + +*/ +package tencentcloud + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + tcr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcr/v20190924" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func resourceTencentCloudTcrTagRetentionRule() *schema.Resource { + return &schema.Resource{ + Create: resourceTencentCloudTcrTagRetentionRuleCreate, + Read: resourceTencentCloudTcrTagRetentionRuleRead, + Update: resourceTencentCloudTcrTagRetentionRuleUpdate, + Delete: resourceTencentCloudTcrTagRetentionRuleDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "registry_id": { + Required: true, + Type: schema.TypeString, + Description: "The main instance ID.", + }, + + "namespace_name": { + Required: true, + Type: schema.TypeString, + Description: "The Name of the namespace.", + }, + + "retention_rule": { + Required: true, + Type: schema.TypeList, + MaxItems: 1, + Description: "Retention Policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + Description: "The supported policies are latestPushedK (retain the latest `k` pushed versions) and nDaysSinceLastPush (retain pushed versions within the last `n` days).", + }, + "value": { + Type: schema.TypeInt, + Required: true, + Description: "corresponding values for rule settings.", + }, + }, + }, + }, + + "cron_setting": { + Required: true, + Type: schema.TypeString, + Description: "Execution cycle, currently only available selections are: manual; daily; weekly; monthly.", + }, + + "disabled": { + Optional: true, + Type: schema.TypeBool, + Description: "Whether to disable the rule, with the default value of false.", + }, + }, + } +} + +func resourceTencentCloudTcrTagRetentionRuleCreate(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_tcr_tag_retention_rule.create")() + defer inconsistentCheck(d, meta)() + + var ( + logId = getLogId(contextNil) + ctx = context.WithValue(context.TODO(), logIdKey, logId) + request = tcr.NewCreateTagRetentionRuleRequest() + registryId string + namespaceId string + namespaceName string + tcrService = TCRService{client: meta.(*TencentCloudClient).apiV3Conn} + ) + if v, ok := d.GetOk("registry_id"); ok { + registryId = v.(string) + request.RegistryId = helper.String(v.(string)) + } + + if v, ok := d.GetOkExists("namespace_id"); ok { + namespaceId = helper.Int64ToStr(v.(int64)) + request.NamespaceId = helper.IntInt64(v.(int)) + } + + if v, ok := d.GetOk("namespace_name"); ok { + namespaceName = v.(string) + namespace, has, err := tcrService.DescribeTCRNameSpaceById(ctx, registryId, namespaceName) + if !has || namespace == nil { + return fmt.Errorf("TCR namespace not found.") + } + if err != nil { + return err + } + request.NamespaceId = namespace.NamespaceId + } + + if dMap, ok := helper.InterfacesHeadMap(d, "retention_rule"); ok { + retentionRule := tcr.RetentionRule{} + if v, ok := dMap["key"]; ok { + retentionRule.Key = helper.String(v.(string)) + } + if v, ok := dMap["value"]; ok { + retentionRule.Value = helper.IntInt64(v.(int)) + } + request.RetentionRule = &retentionRule + } + + if v, ok := d.GetOk("cron_setting"); ok { + request.CronSetting = helper.String(v.(string)) + } + + if v, ok := d.GetOkExists("disabled"); ok { + request.Disabled = helper.Bool(v.(bool)) + } + + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { + result, e := meta.(*TencentCloudClient).apiV3Conn.UseTCRClient().CreateTagRetentionRule(request) + if e != nil { + return retryError(e) + } else { + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) + } + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s create tcr TagRetentionRule failed, reason:%+v", logId, err) + return err + } + + TagRetentionRule, err := tcrService.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, nil) + if err != nil { + return fmt.Errorf("Query retention rule by id failed, reason:[%s]", err.Error()) + } + + if TagRetentionRule != nil { + retentionId := helper.Int64ToStr(*TagRetentionRule.RetentionId) + d.SetId(strings.Join([]string{registryId, namespaceId, retentionId}, FILED_SP)) + } else { + log.Printf("[CRITAL]%s TagRetentionRule is nil! Set unique id as empty.", logId) + d.SetId("") + } + + return resourceTencentCloudTcrTagRetentionRuleRead(d, meta) +} + +func resourceTencentCloudTcrTagRetentionRuleRead(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_tcr_tag_retention_rule.read")() + defer inconsistentCheck(d, meta)() + + logId := getLogId(contextNil) + + ctx := context.WithValue(context.TODO(), logIdKey, logId) + + service := TCRService{client: meta.(*TencentCloudClient).apiV3Conn} + + idSplit := strings.Split(d.Id(), FILED_SP) + if len(idSplit) != 3 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + registryId := idSplit[0] + namespaceName := idSplit[1] + retentionId := idSplit[2] + + TagRetentionRule, err := service.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, &retentionId) + if err != nil { + return err + } + + if TagRetentionRule == nil { + d.SetId("") + log.Printf("[WARN]%s resource `TcrTagRetentionRule` [%s] not found, please check if it has been deleted.\n", logId, d.Id()) + return nil + } + + if TagRetentionRule.NamespaceName != nil { + _ = d.Set("namespace_name", TagRetentionRule.NamespaceName) + } + + if len(TagRetentionRule.RetentionRuleList) > 0 { + retentionRuleMap := map[string]interface{}{} + retentionRule := TagRetentionRule.RetentionRuleList[0] + + if retentionRule.Key != nil { + retentionRuleMap["key"] = retentionRule.Key + } + + if retentionRule.Value != nil { + retentionRuleMap["value"] = retentionRule.Value + } + + _ = d.Set("retention_rule", []interface{}{retentionRuleMap}) + } + + if TagRetentionRule.CronSetting != nil { + _ = d.Set("cron_setting", TagRetentionRule.CronSetting) + } + + if TagRetentionRule.Disabled != nil { + _ = d.Set("disabled", TagRetentionRule.Disabled) + } + + return nil +} + +func resourceTencentCloudTcrTagRetentionRuleUpdate(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_tcr_tag_retention_rule.update")() + defer inconsistentCheck(d, meta)() + + logId := getLogId(contextNil) + + request := tcr.NewModifyTagRetentionRuleRequest() + tcrService := TCRService{client: meta.(*TencentCloudClient).apiV3Conn} + ctx := context.WithValue(context.TODO(), logIdKey, logId) + + idSplit := strings.Split(d.Id(), FILED_SP) + if len(idSplit) != 3 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + registryId := idSplit[0] + namespaceName := idSplit[1] + retentionId := idSplit[2] + + namespace, has, err := tcrService.DescribeTCRNameSpaceById(ctx, registryId, namespaceName) + if !has || namespace == nil { + return fmt.Errorf("TCR namespace not found.") + } + if err != nil { + return err + } + + request.RegistryId = ®istryId + request.NamespaceId = namespace.NamespaceId + request.RetentionId = helper.StrToInt64Point(retentionId) + + immutableArgs := []string{"registry_id", "namespace_name", "cron_setting"} + + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) + } + } + + if d.HasChange("retention_rule") { + if dMap, ok := helper.InterfacesHeadMap(d, "retention_rule"); ok { + retentionRule := tcr.RetentionRule{} + if v, ok := dMap["key"]; ok { + retentionRule.Key = helper.String(v.(string)) + } + if v, ok := dMap["value"]; ok { + retentionRule.Value = helper.IntInt64(v.(int)) + } + request.RetentionRule = &retentionRule + } + } + + if d.HasChange("disabled") { + if v, ok := d.GetOkExists("disabled"); ok { + request.Disabled = helper.Bool(v.(bool)) + } + } + + err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { + result, e := meta.(*TencentCloudClient).apiV3Conn.UseTCRClient().ModifyTagRetentionRule(request) + if e != nil { + return retryError(e) + } else { + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) + } + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s update tcr TagRetentionRule failed, reason:%+v", logId, err) + return err + } + + return resourceTencentCloudTcrTagRetentionRuleRead(d, meta) +} + +func resourceTencentCloudTcrTagRetentionRuleDelete(d *schema.ResourceData, meta interface{}) error { + defer logElapsed("resource.tencentcloud_tcr_tag_retention_rule.delete")() + defer inconsistentCheck(d, meta)() + + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + + service := TCRService{client: meta.(*TencentCloudClient).apiV3Conn} + idSplit := strings.Split(d.Id(), FILED_SP) + if len(idSplit) != 3 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + registryId := idSplit[0] + retentionId := idSplit[2] + + if err := service.DeleteTcrTagRetentionRuleById(ctx, registryId, retentionId); err != nil { + return err + } + + return nil +} diff --git a/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go new file mode 100644 index 0000000000..0ee6fa5360 --- /dev/null +++ b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go @@ -0,0 +1,134 @@ +package tencentcloud + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccTencentCloudTCRTagRetentionRuleResource_basic(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckTCRTagRetentionRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTcrTagRetentionRule, + Check: resource.ComposeTestCheckFunc( + testAccCheckTCRTagRetentionRuleExists("tencentcloud_tcr_tag_retention_rule.my_rule"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "id"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "registry_id"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "namespace_name", "tf_test_ns_retention"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.#"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.0.key", "nDaysSinceLastPush"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.1.value", "1"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "cron_setting", "manual"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "disabled", "false"), + ), + }, + { + ResourceName: "tencentcloud_tcr_tag_retention_rule.my_rule", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckTCRTagRetentionRuleDestroy(s *terraform.State) error { + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + + service := TCRService{client: testAccProvider.Meta().(*TencentCloudClient).apiV3Conn} + for _, rs := range s.RootModule().Resources { + if rs.Type != "tencentcloud_tcr_tag_retention_rule" { + continue + } + + idSplit := strings.Split(rs.Primary.ID, FILED_SP) + if len(idSplit) != 3 { + return fmt.Errorf("id is broken,%s", rs.Primary.ID) + } + registryId := idSplit[0] + namespaceName := idSplit[1] + retentionId := idSplit[2] + + rule, err := service.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, &retentionId) + if err != nil { + return err + } + + if rule != nil { + return fmt.Errorf("Tcr Tag Retention Rule still exist, Id: %v", rs.Primary.ID) + } + } + return nil +} + +func testAccCheckTCRTagRetentionRuleExists(re string) resource.TestCheckFunc { + return func(s *terraform.State) error { + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + service := TCRService{client: testAccProvider.Meta().(*TencentCloudClient).apiV3Conn} + + rs, ok := s.RootModule().Resources[re] + if !ok { + return fmt.Errorf("Tcr Tag Retention Rule %s is not found", re) + } + if rs.Primary.ID == "" { + return fmt.Errorf("Tcr Tag Retention Rule id is not set") + } + + idSplit := strings.Split(rs.Primary.ID, FILED_SP) + if len(idSplit) != 3 { + return fmt.Errorf("id is broken,%s", rs.Primary.ID) + } + registryId := idSplit[0] + namespaceName := idSplit[1] + retentionId := idSplit[2] + + rule, err := service.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, &retentionId) + if err != nil { + return err + } + + if rule == nil { + return fmt.Errorf("Tcr Tag Retention Rule not found, Id: %v", rs.Primary.ID) + } + return nil + } +} + +const testAccTcrTagRetentionRule = defaultTCRInstanceData + ` + +resource "tencentcloud_tcr_namespace" "my_ns" { + instance_id = local.tcr_id + name = "tf_test_ns_retention" + is_public = true + is_auto_scan = true + is_prevent_vul = true + severity = "medium" + cve_whitelist_items { + cve_id = "cve-xxxxx" + } +} + +resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { + registry_id = local.tcr_id + namespace_name = tencentcloud_tcr_namespace.my_ns.name + retention_rule { + key = "nDaysSinceLastPush" + value = 1 + } + cron_setting = "manual" + disabled = false +} + +` diff --git a/tencentcloud/service_tencentcloud_tcr.go b/tencentcloud/service_tencentcloud_tcr.go index 2ae5ce0020..5353613af7 100644 --- a/tencentcloud/service_tencentcloud_tcr.go +++ b/tencentcloud/service_tencentcloud_tcr.go @@ -1033,3 +1033,68 @@ func (me *TCRService) DescribeReplicationInstances(ctx context.Context, request return } + +func (me *TCRService) DescribeTcrTagRetentionRuleById(ctx context.Context, registryId, namespaceName string, retentionId *string) (TagRetentionRule *tcr.RetentionPolicy, errRet error) { + logId := getLogId(ctx) + + request := tcr.NewDescribeTagRetentionRulesRequest() + request.RegistryId = ®istryId + request.NamespaceName = &namespaceName + + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + ratelimit.Check(request.GetAction()) + + response, err := me.client.UseTCRClient().DescribeTagRetentionRules(request) + if err != nil { + errRet = err + return + } + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + if len(response.Response.RetentionPolicyList) < 1 { + return + } + + if retentionId != nil { + for _, policy := range response.Response.RetentionPolicyList { + if *policy.RetentionId == helper.StrToInt64(*retentionId) { + TagRetentionRule = policy + return + } + } + return nil, fmt.Errorf("[ERROR]%sThe TagRetentionRules[%v] not found in the qurey results. \n", logId, *retentionId) + } + + TagRetentionRule = response.Response.RetentionPolicyList[0] + return +} + +func (me *TCRService) DeleteTcrTagRetentionRuleById(ctx context.Context, registryId string, retentionId string) (errRet error) { + logId := getLogId(ctx) + + request := tcr.NewDeleteTagRetentionRuleRequest() + request.RegistryId = ®istryId + request.RetentionId = helper.StrToInt64Point(retentionId) + + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + ratelimit.Check(request.GetAction()) + + response, err := me.client.UseTCRClient().DeleteTagRetentionRule(request) + if err != nil { + errRet = err + return + } + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + return +} diff --git a/website/docs/r/tcr_tag_retention_rule.html.markdown b/website/docs/r/tcr_tag_retention_rule.html.markdown new file mode 100644 index 0000000000..039d33a1b8 --- /dev/null +++ b/website/docs/r/tcr_tag_retention_rule.html.markdown @@ -0,0 +1,63 @@ +--- +subcategory: "Tencent Container Registry(TCR)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_tcr_tag_retention_rule" +sidebar_current: "docs-tencentcloud-resource-tcr_tag_retention_rule" +description: |- + Provides a resource to create a tcr tag_retention_rule +--- + +# tencentcloud_tcr_tag_retention_rule + +Provides a resource to create a tcr tag_retention_rule + +## Example Usage + +```hcl +resource "tencentcloud_tcr_namespace" "my_ns" { + instance_id = local.tcr_id + name = "tf_test_ns_retention" + is_public = true + is_auto_scan = true + is_prevent_vul = true + severity = "medium" + cve_whitelist_items { + cve_id = "cve-xxxxx" + } +} + +resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { + registry_id = local.tcr_id + namespace_name = tencentcloud_tcr_namespace.my_ns.name + retention_rule { + key = "nDaysSinceLastPush" + value = 1 + } + cron_setting = "manual" + disabled = false +} +``` + +## Argument Reference + +The following arguments are supported: + +* `cron_setting` - (Required, String) Execution cycle, currently only available selections are: manual; daily; weekly; monthly. +* `namespace_name` - (Required, String) The Name of the namespace. +* `registry_id` - (Required, String) The main instance ID. +* `retention_rule` - (Required, List) Retention Policy. +* `disabled` - (Optional, Bool) Whether to disable the rule, with the default value of false. + +The `retention_rule` object supports the following: + +* `key` - (Required, String) The supported policies are latestPushedK (retain the latest `k` pushed versions) and nDaysSinceLastPush (retain pushed versions within the last `n` days). +* `value` - (Required, Int) corresponding values for rule settings. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. + + + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 1b20e1d2f7..2bb6b9d4f0 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -2190,6 +2190,9 @@
  • tencentcloud_tcr_repository
  • +
  • + tencentcloud_tcr_tag_retention_rule +
  • tencentcloud_tcr_token
  • From d6ec91c74b7d2095f23d44c365f452c4967b6c34 Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Wed, 12 Apr 2023 18:17:58 +0800 Subject: [PATCH 2/3] add changelog --- .changelog/1668.txt | 3 ++ .../resource_tc_tcr_tag_retention_rule.go | 15 +++--- ...resource_tc_tcr_tag_retention_rule_test.go | 47 +++++++++++++++++-- .../r/tcr_tag_retention_rule.html.markdown | 6 +-- 4 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 .changelog/1668.txt diff --git a/.changelog/1668.txt b/.changelog/1668.txt new file mode 100644 index 0000000000..9104e96ba7 --- /dev/null +++ b/.changelog/1668.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +tencentcloud_tcr_tag_retention_rule +``` \ No newline at end of file diff --git a/tencentcloud/resource_tc_tcr_tag_retention_rule.go b/tencentcloud/resource_tc_tcr_tag_retention_rule.go index 091d19c23c..39d42b2a7b 100644 --- a/tencentcloud/resource_tc_tcr_tag_retention_rule.go +++ b/tencentcloud/resource_tc_tcr_tag_retention_rule.go @@ -21,10 +21,10 @@ resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { namespace_name = tencentcloud_tcr_namespace.my_ns.name retention_rule { key = "nDaysSinceLastPush" - value = 1 + value = 2 } - cron_setting = "manual" - disabled = false + cron_setting = "daily" + disabled = true } ``` @@ -110,7 +110,6 @@ func resourceTencentCloudTcrTagRetentionRuleCreate(d *schema.ResourceData, meta ctx = context.WithValue(context.TODO(), logIdKey, logId) request = tcr.NewCreateTagRetentionRuleRequest() registryId string - namespaceId string namespaceName string tcrService = TCRService{client: meta.(*TencentCloudClient).apiV3Conn} ) @@ -120,7 +119,6 @@ func resourceTencentCloudTcrTagRetentionRuleCreate(d *schema.ResourceData, meta } if v, ok := d.GetOkExists("namespace_id"); ok { - namespaceId = helper.Int64ToStr(v.(int64)) request.NamespaceId = helper.IntInt64(v.(int)) } @@ -176,7 +174,7 @@ func resourceTencentCloudTcrTagRetentionRuleCreate(d *schema.ResourceData, meta if TagRetentionRule != nil { retentionId := helper.Int64ToStr(*TagRetentionRule.RetentionId) - d.SetId(strings.Join([]string{registryId, namespaceId, retentionId}, FILED_SP)) + d.SetId(strings.Join([]string{registryId, namespaceName, retentionId}, FILED_SP)) } else { log.Printf("[CRITAL]%s TagRetentionRule is nil! Set unique id as empty.", logId) d.SetId("") @@ -214,6 +212,8 @@ func resourceTencentCloudTcrTagRetentionRuleRead(d *schema.ResourceData, meta in return nil } + _ = d.Set("registry_id", registryId) + if TagRetentionRule.NamespaceName != nil { _ = d.Set("namespace_name", TagRetentionRule.NamespaceName) } @@ -273,6 +273,9 @@ func resourceTencentCloudTcrTagRetentionRuleUpdate(d *schema.ResourceData, meta request.RegistryId = ®istryId request.NamespaceId = namespace.NamespaceId request.RetentionId = helper.StrToInt64Point(retentionId) + if v, ok := d.GetOkExists("cron_setting"); ok { + request.CronSetting = helper.String(v.(string)) + } immutableArgs := []string{"registry_id", "namespace_name", "cron_setting"} diff --git a/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go index 0ee6fa5360..90b8f57c2d 100644 --- a/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go +++ b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go @@ -28,11 +28,25 @@ func TestAccTencentCloudTCRTagRetentionRuleResource_basic(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "namespace_name", "tf_test_ns_retention"), resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.#"), resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.0.key", "nDaysSinceLastPush"), - resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.1.value", "1"), - resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "cron_setting", "manual"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.0.value", "1"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "cron_setting", "daily"), resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "disabled", "false"), ), }, + { + Config: testAccTcrTagRetentionRule_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckTCRTagRetentionRuleExists("tencentcloud_tcr_tag_retention_rule.my_rule"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "id"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "registry_id"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "namespace_name", "tf_test_ns_retention"), + resource.TestCheckResourceAttrSet("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.#"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.0.key", "nDaysSinceLastPush"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "retention_rule.0.value", "2"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "cron_setting", "daily"), + resource.TestCheckResourceAttr("tencentcloud_tcr_tag_retention_rule.my_rule", "disabled", "true"), + ), + }, { ResourceName: "tencentcloud_tcr_tag_retention_rule.my_rule", ImportState: true, @@ -127,8 +141,35 @@ resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { key = "nDaysSinceLastPush" value = 1 } - cron_setting = "manual" + cron_setting = "daily" disabled = false } ` + +const testAccTcrTagRetentionRule_update = defaultTCRInstanceData + ` + +resource "tencentcloud_tcr_namespace" "my_ns" { + instance_id = local.tcr_id + name = "tf_test_ns_retention" + is_public = true + is_auto_scan = true + is_prevent_vul = true + severity = "medium" + cve_whitelist_items { + cve_id = "cve-xxxxx" + } +} + +resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { + registry_id = local.tcr_id + namespace_name = tencentcloud_tcr_namespace.my_ns.name + retention_rule { + key = "nDaysSinceLastPush" + value = 2 + } + cron_setting = "daily" + disabled = true +} + +` diff --git a/website/docs/r/tcr_tag_retention_rule.html.markdown b/website/docs/r/tcr_tag_retention_rule.html.markdown index 039d33a1b8..224cba6f66 100644 --- a/website/docs/r/tcr_tag_retention_rule.html.markdown +++ b/website/docs/r/tcr_tag_retention_rule.html.markdown @@ -31,10 +31,10 @@ resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { namespace_name = tencentcloud_tcr_namespace.my_ns.name retention_rule { key = "nDaysSinceLastPush" - value = 1 + value = 2 } - cron_setting = "manual" - disabled = false + cron_setting = "daily" + disabled = true } ``` From d36f4ed036aa4adba3138fc70eaf256a177ef34b Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Mon, 17 Apr 2023 14:50:59 +0800 Subject: [PATCH 3/3] adjust e2e case for tcr repo and retention rule --- .../resource_tc_tcr_repository_test.go | 59 +++++++++++++++++++ ...resource_tc_tcr_tag_retention_rule_test.go | 34 +++++++++-- 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/tencentcloud/resource_tc_tcr_repository_test.go b/tencentcloud/resource_tc_tcr_repository_test.go index 7ef299b60d..4e38b3bfae 100644 --- a/tencentcloud/resource_tc_tcr_repository_test.go +++ b/tencentcloud/resource_tc_tcr_repository_test.go @@ -8,8 +8,67 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" + tcr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tcr/v20190924" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" ) +func init() { + resource.AddTestSweepers("tencentcloud_tcr_repository", &resource.Sweeper{ + Name: "tencentcloud_tcr_repository", + F: testSweepTCRRepository, + }) +} + +// go test -v ./tencentcloud -sweep=ap-guangzhou -sweep-run=tencentcloud_tcr_repository +func testSweepTCRRepository(r string) error { + logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + cli, _ := sharedClientForRegion(r) + tcrService := TCRService{client: cli.(*TencentCloudClient).apiV3Conn} + + var filters []*tcr.Filter + filters = append(filters, &tcr.Filter{ + Name: helper.String("RegistryName"), + Values: []*string{helper.String(defaultTCRInstanceName)}, + }) + + instances, err := tcrService.DescribeTCRInstances(ctx, "", filters) + + if err != nil { + return err + } + + if len(instances) == 0 { + return fmt.Errorf("instance %s not exist", defaultTCRInstanceName) + } + + instanceId := *instances[0].RegistryId + // the non-keep namespace will be removed directly when run sweeper tencentcloud_tcr_namespace + // so... only need to care about the repos under the keep namespace + repos, err := tcrService.DescribeTCRRepositories(ctx, instanceId, "", "") + + if err != nil { + return err + } + + for i := range repos { + n := repos[i] + names := strings.Split(*n.Name, "/") + if len(names) != 2 { + continue + } + repoName := names[1] + if isResourcePersist(repoName, nil) { + continue + } + err = tcrService.DeleteTCRRepository(ctx, instanceId, *n.Namespace, repoName) + if err != nil { + continue + } + } + return nil +} + func TestAccTencentCloudTCRRepository_basic_and_update(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ diff --git a/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go index 90b8f57c2d..0d757bbcfc 100644 --- a/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go +++ b/tencentcloud/resource_tc_tcr_tag_retention_rule_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" ) func TestAccTencentCloudTCRTagRetentionRuleResource_basic(t *testing.T) { @@ -76,6 +77,11 @@ func testAccCheckTCRTagRetentionRuleDestroy(s *terraform.State) error { rule, err := service.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, &retentionId) if err != nil { + if ee, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if ee.Code == "ResourceNotFound" { + return nil + } + } return err } @@ -110,6 +116,11 @@ func testAccCheckTCRTagRetentionRuleExists(re string) resource.TestCheckFunc { rule, err := service.DescribeTcrTagRetentionRuleById(ctx, registryId, namespaceName, &retentionId) if err != nil { + if ee, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if ee.Code == "ResourceNotFound" { + return fmt.Errorf("Tcr Tag Retention Rule not found[ResourceNotFound], Id: %v", rs.Primary.ID) + } + } return err } @@ -120,10 +131,21 @@ func testAccCheckTCRTagRetentionRuleExists(re string) resource.TestCheckFunc { } } -const testAccTcrTagRetentionRule = defaultTCRInstanceData + ` +const testAccTCRInstance_retention = ` +resource "tencentcloud_tcr_instance" "mytcr_retention" { + name = "tf-test-tcr-retention" + instance_type = "basic" + delete_bucket = true + + tags ={ + test = "test" + } +}` + +const testAccTcrTagRetentionRule = testAccTCRInstance_retention + ` resource "tencentcloud_tcr_namespace" "my_ns" { - instance_id = local.tcr_id + instance_id = tencentcloud_tcr_instance.mytcr_retention.id name = "tf_test_ns_retention" is_public = true is_auto_scan = true @@ -135,7 +157,7 @@ resource "tencentcloud_tcr_namespace" "my_ns" { } resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { - registry_id = local.tcr_id + registry_id = tencentcloud_tcr_instance.mytcr_retention.id namespace_name = tencentcloud_tcr_namespace.my_ns.name retention_rule { key = "nDaysSinceLastPush" @@ -147,10 +169,10 @@ resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { ` -const testAccTcrTagRetentionRule_update = defaultTCRInstanceData + ` +const testAccTcrTagRetentionRule_update = testAccTCRInstance_retention + ` resource "tencentcloud_tcr_namespace" "my_ns" { - instance_id = local.tcr_id + instance_id = tencentcloud_tcr_instance.mytcr_retention.id name = "tf_test_ns_retention" is_public = true is_auto_scan = true @@ -162,7 +184,7 @@ resource "tencentcloud_tcr_namespace" "my_ns" { } resource "tencentcloud_tcr_tag_retention_rule" "my_rule" { - registry_id = local.tcr_id + registry_id = tencentcloud_tcr_instance.mytcr_retention.id namespace_name = tencentcloud_tcr_namespace.my_ns.name retention_rule { key = "nDaysSinceLastPush"