From ae40d24afa969fb6574550d5fa2a525383a402d7 Mon Sep 17 00:00:00 2001 From: hoanglm Date: Fri, 15 Nov 2024 18:16:17 +0700 Subject: [PATCH] [Object Storage] fix: fix payload bucket lifecycle --- .../datasource_list_bucket_lifecycle.tf | 4 +- .../datasource_list_bucket_static_website.tf | 4 +- .../resource_bucket_lifecycle.tf | 12 ++++ .../datasource_object_storage.go | 12 ++-- .../datasource_object_storage_bucket.go | 4 +- .../datasource_object_storage_bucket_cors.go | 4 +- ...asource_object_storage_bucket_lifecycle.go | 44 +++++++++---- .../datasource_object_storage_sub_user.go | 4 +- .../resource_bucket_lifecycle.go | 65 ++++++++++++++++--- fptcloud/provider.go | 4 +- 10 files changed, 119 insertions(+), 38 deletions(-) create mode 100644 examples/resources/fptcloud_object_storage/resource_bucket_lifecycle.tf diff --git a/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_lifecycle.tf b/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_lifecycle.tf index 2fd519e..177ef39 100644 --- a/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_lifecycle.tf +++ b/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_lifecycle.tf @@ -1,4 +1,4 @@ -data "fptcloud_object_storage_lifecycle" "example_bucket_lifecycle" { +data "fptcloud_object_storage_bucket_lifecycle" "example_bucket_lifecycle" { vpc_id = "your_vpc_id" region_name = "your_region_name" bucket_name = "your_bucket_name" @@ -7,5 +7,5 @@ data "fptcloud_object_storage_lifecycle" "example_bucket_lifecycle" { } output "bucket_lifecycle" { - value = data.fptcloud_object_storage_lifecycle.example_bucket_lifecycle + value = data.fptcloud_object_storage_bucket_lifecycle.example_bucket_lifecycle } diff --git a/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_static_website.tf b/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_static_website.tf index ae1846e..21484aa 100644 --- a/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_static_website.tf +++ b/examples/data-sources/fptcloud_object_storage/datasource_list_bucket_static_website.tf @@ -1,9 +1,9 @@ -data "fptcloud_object_storage_static_website" "example_bucket_static_website" { +data "fptcloud_object_storage_bucket_static_website" "example_bucket_static_website" { vpc_id = "your_vpc_id" region_name = "your_region_name" bucket_name = "your_bucket_name" } output "bucket_static_website" { - value = data.fptcloud_object_storage_static_website.example_bucket_static_website + value = data.fptcloud_object_storage_bucket_static_website.example_bucket_static_website } diff --git a/examples/resources/fptcloud_object_storage/resource_bucket_lifecycle.tf b/examples/resources/fptcloud_object_storage/resource_bucket_lifecycle.tf new file mode 100644 index 0000000..22b80cb --- /dev/null +++ b/examples/resources/fptcloud_object_storage/resource_bucket_lifecycle.tf @@ -0,0 +1,12 @@ +resource "fptcloud_object_storage_bucket_lifecycle" "example_bucket_lifecycle" { + bucket_name = "your_bucket_name" + region_name = "your_region_name" + vpc_id = "your_vpc_id" + + # Option 1: Load policy from file + life_cycle_rule_file = file("${path.module}/your_bucket_lifecycle.json") +} + +output "bucket_lifecycle" { + value = fptcloud_object_storage_bucket_lifecycle.example_bucket_lifecycle +} diff --git a/fptcloud/object-storage/datasource_object_storage.go b/fptcloud/object-storage/datasource_object_storage.go index e380136..b828c22 100644 --- a/fptcloud/object-storage/datasource_object_storage.go +++ b/fptcloud/object-storage/datasource_object_storage.go @@ -3,6 +3,7 @@ package fptcloud_object_storage import ( "encoding/json" "fmt" + "log" common "terraform-provider-fptcloud/commons" ) @@ -299,7 +300,7 @@ type ObjectStorageService interface { DeleteBucketStaticWebsite(vpcId, s3ServiceId, bucketName string) CommonResponse // Lifecycle configuration - GetBucketLifecycle(vpcId, s3ServiceId, bucketName string, page, pageSize int) (*BucketLifecycleResponse, error) + GetBucketLifecycle(vpcId, s3ServiceId, bucketName string, page, pageSize int) BucketLifecycleResponse PutBucketLifecycle(vpcId, s3ServiceId, bucketName string, lifecycle map[string]interface{}) CommonResponse DeleteBucketLifecycle(vpcId, s3ServiceId, bucketName string, lifecycle map[string]interface{}) CommonResponse } @@ -587,18 +588,19 @@ func (s *ObjectStorageServiceImpl) DeleteSubUser(vpcId, s3ServiceId, subUserId s return nil } -func (s *ObjectStorageServiceImpl) GetBucketLifecycle(vpcId, s3ServiceId, bucketName string, page, pageSize int) (*BucketLifecycleResponse, error) { +func (s *ObjectStorageServiceImpl) GetBucketLifecycle(vpcId, s3ServiceId, bucketName string, page, pageSize int) BucketLifecycleResponse { + log.Printf("[DEBUG] GetBucketLifecycle: %s, %s, %s, %d, %d", vpcId, s3ServiceId, bucketName, page, pageSize) apiPath := common.ApiPath.GetBucketLifecycle(vpcId, s3ServiceId, bucketName, page, pageSize) resp, err := s.client.SendGetRequest(apiPath) if err != nil { - return nil, fmt.Errorf("failed to get bucket lifecycle: %v", err) + return BucketLifecycleResponse{Total: 0, Status: false} } var bucketLifecycle BucketLifecycleResponse if err := json.Unmarshal(resp, &bucketLifecycle); err != nil { - return nil, fmt.Errorf("failed to unmarshal bucket lifecycle: %v", err) + return BucketLifecycleResponse{Total: 0, Status: false} } - return &bucketLifecycle, nil + return bucketLifecycle } func (s *ObjectStorageServiceImpl) PutBucketLifecycle(vpcId, s3ServiceId, bucketName string, lifecycle map[string]interface{}) CommonResponse { diff --git a/fptcloud/object-storage/datasource_object_storage_bucket.go b/fptcloud/object-storage/datasource_object_storage_bucket.go index 29b825e..f09fc39 100644 --- a/fptcloud/object-storage/datasource_object_storage_bucket.go +++ b/fptcloud/object-storage/datasource_object_storage_bucket.go @@ -76,11 +76,11 @@ func dataSourceBucketRead(ctx context.Context, d *schema.ResourceData, m interfa service := NewObjectStorageService(client) vpcId := d.Get("vpc_id").(string) page := 1 - if d.Get("page") != nil { + if d.Get("page").(int) > 0 { page = d.Get("page").(int) } pageSize := 25 - if d.Get("page_size") != nil { + if d.Get("page_size").(int) > 0 { pageSize = d.Get("page_size").(int) } regionName := d.Get("region_name").(string) diff --git a/fptcloud/object-storage/datasource_object_storage_bucket_cors.go b/fptcloud/object-storage/datasource_object_storage_bucket_cors.go index 8d5f419..4a3f907 100644 --- a/fptcloud/object-storage/datasource_object_storage_bucket_cors.go +++ b/fptcloud/object-storage/datasource_object_storage_bucket_cors.go @@ -98,11 +98,11 @@ func dataSourceBucketCorsRead(ctx context.Context, d *schema.ResourceData, m int } bucketName := d.Get("bucket_name").(string) page := 1 - if d.Get("page") != nil { + if d.Get("page").(int) > 0 { page = d.Get("page").(int) } pageSize := 25 - if d.Get("page_size") != nil { + if d.Get("page_size").(int) > 0 { pageSize = d.Get("page_size").(int) } corsRule, err := service.GetBucketCors(vpcId, s3ServiceDetail.S3ServiceId, bucketName, page, pageSize) diff --git a/fptcloud/object-storage/datasource_object_storage_bucket_lifecycle.go b/fptcloud/object-storage/datasource_object_storage_bucket_lifecycle.go index 1866d0c..5b09af0 100644 --- a/fptcloud/object-storage/datasource_object_storage_bucket_lifecycle.go +++ b/fptcloud/object-storage/datasource_object_storage_bucket_lifecycle.go @@ -3,6 +3,7 @@ package fptcloud_object_storage import ( "context" "fmt" + "log" common "terraform-provider-fptcloud/commons" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -63,11 +64,19 @@ func DataSourceBucketLifecycle() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "prefix": { + Type: schema.TypeString, + Computed: true, + }, "expiration": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "days": { + Type: schema.TypeInt, + Computed: true, + }, "expired_object_delete_marker": { Type: schema.TypeBool, Computed: true, @@ -118,25 +127,26 @@ func dataSourceBucketLifecycleRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(fmt.Errorf("region %s is not enabled", regionName)) } page := 1 - if d.Get("page") != nil { - page = d.Get("page").(int) + v, ok := d.GetOk("page") + if ok { + page = v.(int) } pageSize := 25 - if d.Get("page_size") != nil { - pageSize = d.Get("page_size").(int) + v, ok = d.GetOk("page_size") + if ok { + pageSize = v.(int) } + log.Printf("[DEBUG] FPT CLOUD PAYLOAD with page %d and pageSize %d", page, pageSize) - lifeCycleResponse, err := service.GetBucketLifecycle(vpcId, s3ServiceDetail.S3ServiceId, bucketName, page, pageSize) - if err != nil { - return diag.FromErr(err) - } + lifeCycleResponse := service.GetBucketLifecycle(vpcId, s3ServiceDetail.S3ServiceId, bucketName, page, pageSize) if !lifeCycleResponse.Status { return diag.FromErr(fmt.Errorf("failed to fetch life cycle rules for bucket %s", bucketName)) } d.SetId(bucketName) var formattedData []interface{} + log.Printf("[DEBUG] FPT CLOUD PAYLOAD with lifeCycleResponse %v - %d", lifeCycleResponse.Rules, lifeCycleResponse.Total) if lifeCycleResponse.Total == 0 { - d.Set("life_cycle_rules", formattedData) + d.Set("life_cycle_rules", make([]interface{}, 0)) } for _, lifecycleRule := range lifeCycleResponse.Rules { data := map[string]interface{}{ @@ -152,13 +162,20 @@ func dataSourceBucketLifecycleRead(ctx context.Context, d *schema.ResourceData, "days_after_initiation": lifecycleRule.AbortIncompleteMultipartUpload.DaysAfterInitiation, }, }, - "filter": []interface{}{ + } + // for fully prefix + if lifecycleRule.Prefix == "" { + data["prefix"] = lifecycleRule.Prefix + } + // for filter + if lifecycleRule.Filter.Prefix != "" { + data["filter"] = []interface{}{ map[string]interface{}{ "prefix": lifecycleRule.Filter.Prefix, }, - }, + } } - if lifecycleRule.Expiration.Days != 0 { + if lifecycleRule.Expiration.Days > 0 { data["expiration"] = []interface{}{ map[string]interface{}{ "days": lifecycleRule.Expiration.Days, @@ -174,7 +191,8 @@ func dataSourceBucketLifecycleRead(ctx context.Context, d *schema.ResourceData, } formattedData = append(formattedData, data) } - fmt.Println("DEBUG: formattedData", formattedData) + log.Printf("[DEBUG] FPT CLOUD PAYLOAD with formattedData", formattedData) + if err := d.Set("life_cycle_rules", formattedData); err != nil { d.SetId("") return diag.FromErr(err) diff --git a/fptcloud/object-storage/datasource_object_storage_sub_user.go b/fptcloud/object-storage/datasource_object_storage_sub_user.go index ae91a43..80adf63 100644 --- a/fptcloud/object-storage/datasource_object_storage_sub_user.go +++ b/fptcloud/object-storage/datasource_object_storage_sub_user.go @@ -76,10 +76,10 @@ func dataSourceSubUserRead(ctx context.Context, d *schema.ResourceData, m interf } page := 1 pageSize := 100 - if d.Get("page") != nil { + if d.Get("page").(int) > 0 { page = d.Get("page").(int) } - if d.Get("page_size") != nil { + if d.Get("page_size").(int) > 0 { pageSize = d.Get("page_size").(int) } diff --git a/fptcloud/object-storage/resource_bucket_lifecycle.go b/fptcloud/object-storage/resource_bucket_lifecycle.go index 48d1c4c..7f548b3 100644 --- a/fptcloud/object-storage/resource_bucket_lifecycle.go +++ b/fptcloud/object-storage/resource_bucket_lifecycle.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" common "terraform-provider-fptcloud/commons" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -16,7 +17,7 @@ func ResourceBucketLifeCycle() *schema.Resource { CreateContext: resourceBucketLifeCycleCreate, UpdateContext: nil, DeleteContext: resourceBucketLifeCycleDelete, - ReadContext: dataSourceBucketLifecycleRead, + ReadContext: resourceBucketLifeCycleRead, Schema: map[string]*schema.Schema{ "vpc_id": { Type: schema.TypeString, @@ -51,10 +52,22 @@ func ResourceBucketLifeCycle() *schema.Resource { Description: "Path to the JSON file containing the bucket lifecycle rule, support only one rule", ConflictsWith: []string{"life_cycle_rule"}, }, - "status": { + "state": { Type: schema.TypeBool, Computed: true, - Description: "Status after bucket lifecycle rule is created", + Description: "State after bucket lifecycle rule is created", + }, + "rules": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, }, } @@ -103,17 +116,53 @@ func resourceBucketLifeCycleCreate(ctx context.Context, d *schema.ResourceData, } r := service.PutBucketLifecycle(vpcId, s3ServiceDetail.S3ServiceId, bucketName, payload) if !r.Status { - d.Set("status", false) + d.Set("state", false) return diag.FromErr(fmt.Errorf("%s", r.Message)) } d.SetId(bucketName) - if err := d.Set("status", true); err != nil { + if err := d.Set("state", true); err != nil { return diag.FromErr(err) } return nil } +func resourceBucketLifeCycleRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + client := m.(*common.Client) + service := NewObjectStorageService(client) + bucketName := d.Get("bucket_name").(string) + vpcId := d.Get("vpc_id").(string) + regionName := d.Get("region_name").(string) + s3ServiceDetail := getServiceEnableRegion(service, vpcId, regionName) + if s3ServiceDetail.S3ServiceId == "" { + return diag.FromErr(fmt.Errorf("region %s is not enabled", regionName)) + } + page := 1 + pageSize := 999999 + lifeCycleResponse := service.GetBucketLifecycle(vpcId, s3ServiceDetail.S3ServiceId, bucketName, page, pageSize) + if !lifeCycleResponse.Status { + return diag.FromErr(fmt.Errorf("failed to fetch life cycle rules for bucket %s", bucketName)) + } + d.SetId(bucketName) + var formattedData []interface{} + log.Printf("[DEBUG] FPT CLOUD PAYLOAD with lifeCycleResponse %v - %d", lifeCycleResponse.Rules, lifeCycleResponse.Total) + if lifeCycleResponse.Total == 0 { + d.Set("life_cycle_rules", make([]interface{}, 0)) + } + for _, lifecycleRule := range lifeCycleResponse.Rules { + data := map[string]interface{}{ + "id": lifecycleRule.ID, + } + formattedData = append(formattedData, data) + } + log.Printf("[DEBUG] FPT CLOUD PAYLOAD with formattedData", formattedData) + + if err := d.Set("rules", formattedData); err != nil { + d.SetId("") + return diag.FromErr(err) + } + return nil +} func resourceBucketLifeCycleDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { client := m.(*common.Client) service := NewObjectStorageService(client) @@ -159,12 +208,12 @@ func resourceBucketLifeCycleDelete(ctx context.Context, d *schema.ResourceData, fmt.Println("DATA OF ME PLEASE: ", payload) r := service.DeleteBucketLifecycle(vpcId, s3ServiceDetail.S3ServiceId, bucketName, payload) if !r.Status { - d.Set("status", false) + d.Set("state", false) return diag.FromErr(fmt.Errorf("%s", r.Message)) } d.SetId(bucketName) - if err := d.Set("status", true); err != nil { + if err := d.Set("state", true); err != nil { return diag.FromErr(err) } - return nil + return resourceBucketLifeCycleRead(ctx, d, m) } diff --git a/fptcloud/provider.go b/fptcloud/provider.go index bfe1c44..89c6273 100644 --- a/fptcloud/provider.go +++ b/fptcloud/provider.go @@ -81,8 +81,8 @@ func Provider() *schema.Provider { "fptcloud_object_storage_bucket_policy": fptcloud_object_storage.DataSourceBucketPolicy(), "fptcloud_object_storage_bucket_cors": fptcloud_object_storage.DataSourceBucketCors(), "fptcloud_object_storage_bucket_versioning": fptcloud_object_storage.DataSourceBucketVersioning(), - "fptcloud_object_storage_lifecycle": fptcloud_object_storage.DataSourceBucketLifecycle(), - "fptcloud_object_storage_static_website": fptcloud_object_storage.DataSourceBucketStaticWebsite(), + "fptcloud_object_storage_bucket_lifecycle": fptcloud_object_storage.DataSourceBucketLifecycle(), + "fptcloud_object_storage_bucket_static_website": fptcloud_object_storage.DataSourceBucketStaticWebsite(), "fptcloud_object_storage_sub_user_detail": fptcloud_object_storage.DataSourceSubUserDetail(), "fptcloud_s3_service_enable": fptcloud_object_storage.DataSourceS3ServiceEnableResponse(), "fptcloud_object_storage_bucket_acl": fptcloud_object_storage.DataSourceBucketAcl(),