diff --git a/VERSION b/VERSION index aaaff91..00e897b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.1 \ No newline at end of file +3.8.2 \ No newline at end of file diff --git a/docs/data-sources/review_config.md b/docs/data-sources/review_config.md index bae2a43..d7c42e1 100644 --- a/docs/data-sources/review_config.md +++ b/docs/data-sources/review_config.md @@ -21,7 +21,7 @@ The review config data source. - `id` (String) The ID of this resource. - `resource_id` (String) The unique resource id for the review config. - `resources` (Set of String) Resources using the config. We support attach the review config for environments or projects with format {resurce}/{resource id}. For example, environments/test, projects/sample. -- `rules` (Set of Object) The SQL review rules. (see [below for nested schema](#nestedatt--rules)) +- `rules` (List of Object) The SQL review rules. (see [below for nested schema](#nestedatt--rules)) - `title` (String) The title for the review config. diff --git a/docs/data-sources/review_config_list.md b/docs/data-sources/review_config_list.md index c3bcb7a..73cbf1e 100644 --- a/docs/data-sources/review_config_list.md +++ b/docs/data-sources/review_config_list.md @@ -28,7 +28,7 @@ Read-Only: - `enabled` (Boolean) - `resource_id` (String) - `resources` (Set of String) -- `rules` (Set of Object) (see [below for nested schema](#nestedobjatt--review_configs--rules)) +- `rules` (List of Object) (see [below for nested schema](#nestedobjatt--review_configs--rules)) - `title` (String) diff --git a/docs/data-sources/setting.md b/docs/data-sources/setting.md index fdf13ba..8778482 100644 --- a/docs/data-sources/setting.md +++ b/docs/data-sources/setting.md @@ -36,7 +36,7 @@ The setting data source. Required: -- `classifications` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications)) +- `classifications` (Block List, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications)) - `id` (String) The classification unique uuid. - `levels` (Block List, Min: 1) (see [below for nested schema](#nestedblock--classification--levels)) - `title` (String) The classification title. Optional. diff --git a/docs/resources/review_config.md b/docs/resources/review_config.md index c626056..40b4edb 100644 --- a/docs/resources/review_config.md +++ b/docs/resources/review_config.md @@ -19,7 +19,7 @@ The review config resource. - `enabled` (Boolean) Enable the SQL review config - `resource_id` (String) The unique resource id for the review config. -- `rules` (Block Set, Min: 1) The SQL review rules. (see [below for nested schema](#nestedblock--rules)) +- `rules` (Block List, Min: 1) The SQL review rules. (see [below for nested schema](#nestedblock--rules)) - `title` (String) The title for the review config. ### Optional diff --git a/docs/resources/setting.md b/docs/resources/setting.md index 355791b..0433548 100644 --- a/docs/resources/setting.md +++ b/docs/resources/setting.md @@ -86,7 +86,7 @@ Optional: Required: -- `classifications` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications)) +- `classifications` (Block List, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications)) - `id` (String) The classification unique uuid. - `levels` (Block List, Min: 1) (see [below for nested schema](#nestedblock--classification--levels)) - `title` (String) The classification title. Optional. diff --git a/examples/database/main.tf b/examples/database/main.tf index 2b0e12f..f702ad1 100644 --- a/examples/database/main.tf +++ b/examples/database/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/database_group/main.tf b/examples/database_group/main.tf index 1c0a35f..6f6dbfb 100644 --- a/examples/database_group/main.tf +++ b/examples/database_group/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/environments/main.tf b/examples/environments/main.tf index 1d9dfb7..a7f1c7e 100644 --- a/examples/environments/main.tf +++ b/examples/environments/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/groups/main.tf b/examples/groups/main.tf index e65cbe9..d538995 100644 --- a/examples/groups/main.tf +++ b/examples/groups/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/iamPolicy/main.tf b/examples/iamPolicy/main.tf index 5b6dac1..5094509 100644 --- a/examples/iamPolicy/main.tf +++ b/examples/iamPolicy/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/instances/main.tf b/examples/instances/main.tf index 735e5e5..42c2117 100644 --- a/examples/instances/main.tf +++ b/examples/instances/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/projects/main.tf b/examples/projects/main.tf index 681c99a..43e9060 100644 --- a/examples/projects/main.tf +++ b/examples/projects/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/risk/main.tf b/examples/risk/main.tf index b892277..c23d34a 100644 --- a/examples/risk/main.tf +++ b/examples/risk/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/roles/main.tf b/examples/roles/main.tf index 06c42ba..13f8998 100644 --- a/examples/roles/main.tf +++ b/examples/roles/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/settings/main.tf b/examples/settings/main.tf index a089537..111b301 100644 --- a/examples/settings/main.tf +++ b/examples/settings/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/setup/main.tf b/examples/setup/main.tf index 5f4cfba..44adb6e 100644 --- a/examples/setup/main.tf +++ b/examples/setup/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/sql_review/main.tf b/examples/sql_review/main.tf index 4b38687..271d0ea 100644 --- a/examples/sql_review/main.tf +++ b/examples/sql_review/main.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/examples/users/main.tf b/examples/users/main.tf index 9fca6b1..3eb14cd 100644 --- a/examples/users/main.tf +++ b/examples/users/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { bytebase = { - version = "3.7.2" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" } diff --git a/provider/data_source_database.go b/provider/data_source_database.go index d419cfe..8b500c8 100644 --- a/provider/data_source_database.go +++ b/provider/data_source_database.go @@ -156,7 +156,7 @@ func columnHash(rawColumn interface{}) string { if v, ok := column["classification"].(string); ok { _, _ = buf.WriteString(fmt.Sprintf("%s-", v)) } - if v, ok := column["classification"].(map[string]interface{}); ok { + if v, ok := column["labels"].(map[string]interface{}); ok { for key, val := range v { _, _ = buf.WriteString(fmt.Sprintf("[%s:%s]-", key, val.(string))) } diff --git a/provider/data_source_review_config.go b/provider/data_source_review_config.go index 9ad7f6f..b407099 100644 --- a/provider/data_source_review_config.go +++ b/provider/data_source_review_config.go @@ -40,7 +40,7 @@ func dataSourceReviewConfig() *schema.Resource { Description: "Resources using the config. We support attach the review config for environments or projects with format {resurce}/{resource id}. For example, environments/test, projects/sample.", }, "rules": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Description: "The SQL review rules.", Elem: &schema.Resource{ @@ -72,7 +72,6 @@ func dataSourceReviewConfig() *schema.Resource { }, }, }, - Set: reviewRuleHash, }, }, } diff --git a/provider/data_source_review_config_list.go b/provider/data_source_review_config_list.go index a3d6500..26abd09 100644 --- a/provider/data_source_review_config_list.go +++ b/provider/data_source_review_config_list.go @@ -46,7 +46,7 @@ func dataSourceReviewConfigList() *schema.Resource { Description: "Resources using the config. We support attach the review config for environments or projects with format {resurce}/{resource id}. For example, environments/test, projects/sample.", }, "rules": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Description: "The SQL review rules.", Elem: &schema.Resource{ @@ -78,7 +78,6 @@ func dataSourceReviewConfigList() *schema.Resource { }, }, }, - Set: reviewRuleHash, }, }, }, @@ -106,7 +105,7 @@ func dataSourceReviewConfigListRead(ctx context.Context, d *schema.ResourceData, raw["title"] = review.Title raw["enabled"] = review.Enabled raw["resources"] = review.Resources - raw["rules"] = schema.NewSet(reviewRuleHash, flattenReviewRules(review.Rules)) + raw["rules"] = flattenReviewRules(review.Rules) reviews = append(reviews, raw) } diff --git a/provider/data_source_setting.go b/provider/data_source_setting.go index 3433026..decbf31 100644 --- a/provider/data_source_setting.go +++ b/provider/data_source_setting.go @@ -241,7 +241,7 @@ func getClassificationSetting(computed bool) *schema.Schema { }, "classifications": { Required: true, - Type: schema.TypeSet, + Type: schema.TypeList, MinItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ diff --git a/provider/resource_review_config.go b/provider/resource_review_config.go index bdc6d69..df9f948 100644 --- a/provider/resource_review_config.go +++ b/provider/resource_review_config.go @@ -1,7 +1,6 @@ package provider import ( - "bytes" "context" "fmt" "strings" @@ -54,7 +53,7 @@ func resourceReviewConfig() *schema.Resource { Description: "Resources using the config. We support attach the review config for environments or projects with format {resurce}/{resource id}. For example, environments/test, projects/sample.", }, "rules": { - Type: schema.TypeSet, + Type: schema.TypeList, Required: true, MinItems: 1, Description: "The SQL review rules.", @@ -95,7 +94,6 @@ func resourceReviewConfig() *schema.Resource { }, }, }, - Set: reviewRuleHash, }, }, } @@ -138,18 +136,10 @@ func resourceReviewConfigUpsert(ctx context.Context, d *schema.ResourceData, m i reviewID := d.Get("resource_id").(string) reviewName := fmt.Sprintf("%s%s", internal.ReviewConfigNamePrefix, reviewID) - oldAttachedResources := []string{} if existedName != "" { if existedName != reviewName { return diag.Errorf("cannot change the resource id") } - - existedReview, err := c.GetReviewConfig(ctx, existedName) - if err != nil { - tflog.Debug(ctx, fmt.Sprintf("get review config %s failed with error: %v", existedName, err)) - } else if existedReview != nil { - oldAttachedResources = existedReview.Resources - } } rules, err := convertToV1RuleList(d) @@ -172,13 +162,53 @@ func resourceReviewConfigUpsert(ctx context.Context, d *schema.ResourceData, m i return diag.FromErr(err) } - removeReviewConfigTag(ctx, c, oldAttachedResources) - patchTagPolicy(ctx, c, d, review.Name) + pendingDelete, pendingAdd := getResourceDiff(ctx, c, d) + removeReviewConfigTag(ctx, c, pendingDelete) + patchTagPolicy(ctx, c, review.Name, pendingAdd) d.SetId(review.Name) return resourceReviewConfigRead(ctx, d, m) } +// getResourceDiff returns pending delete list and pending add list. +func getResourceDiff(ctx context.Context, client api.Client, d *schema.ResourceData) ([]string, []string) { + existedName := d.Id() + oldAttachedResources := []string{} + if existedName != "" { + existedReview, err := client.GetReviewConfig(ctx, existedName) + if err != nil { + tflog.Debug(ctx, fmt.Sprintf("get review config %s failed with error: %v", existedName, err)) + } else if existedReview != nil { + oldAttachedResources = existedReview.Resources + } + } + + oldResourceMap := map[string]bool{} + for _, resource := range oldAttachedResources { + oldResourceMap[resource] = true + } + + newAttachedResources := getReviewConfigRelatedResources(d) + newResourceMap := map[string]bool{} + for _, resource := range newAttachedResources { + newResourceMap[resource] = true + } + + pendingDelete := []string{} + pendingAdd := []string{} + for old := range oldResourceMap { + if !newResourceMap[old] { + pendingDelete = append(pendingDelete, old) + } + } + for new := range newResourceMap { + if !oldResourceMap[new] { + pendingAdd = append(pendingAdd, new) + } + } + return pendingDelete, pendingAdd +} + func getReviewConfigRelatedResources(d *schema.ResourceData) []string { resources := []string{} rawSet, ok := d.Get("resources").(*schema.Set) @@ -200,13 +230,8 @@ func removeReviewConfigTag(ctx context.Context, client api.Client, resources []s } } -func patchTagPolicy(ctx context.Context, client api.Client, d *schema.ResourceData, reviewName string) diag.Diagnostics { - rawSet, ok := d.Get("resources").(*schema.Set) - if !ok || rawSet.Len() == 0 { - return nil - } - for _, raw := range rawSet.List() { - resource := raw.(string) +func patchTagPolicy(ctx context.Context, client api.Client, reviewName string, resources []string) diag.Diagnostics { + for _, resource := range resources { if !strings.HasPrefix(resource, internal.ProjectNamePrefix) && !strings.HasPrefix(resource, internal.EnvironmentNamePrefix) { return diag.Errorf("invalid resource, only support projects/{id} or environments/{id}") } @@ -248,7 +273,7 @@ func setReviewConfig(d *schema.ResourceData, review *v1pb.ReviewConfig) diag.Dia if err := d.Set("resources", review.Resources); err != nil { return diag.Errorf("cannot set resources for review: %s", err.Error()) } - if err := d.Set("rules", schema.NewSet(reviewRuleHash, flattenReviewRules(review.Rules))); err != nil { + if err := d.Set("rules", flattenReviewRules(review.Rules)); err != nil { return diag.Errorf("cannot set rules for review: %s", err.Error()) } @@ -269,35 +294,15 @@ func flattenReviewRules(rules []*v1pb.SQLReviewRule) []interface{} { return ruleList } -func reviewRuleHash(rawRule interface{}) int { - var buf bytes.Buffer - raw := rawRule.(map[string]interface{}) - - if v, ok := raw["type"].(string); ok { - _, _ = buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := raw["engine"].(string); ok { - _, _ = buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := raw["payload"].(string); ok { - _, _ = buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := raw["level"].(string); ok { - _, _ = buf.WriteString(fmt.Sprintf("%s-", v)) - } - - return internal.ToHashcodeInt(buf.String()) -} - func convertToV1RuleList(d *schema.ResourceData) ([]*v1pb.SQLReviewRule, error) { - ruleSet, ok := d.Get("rules").(*schema.Set) - if !ok || ruleSet.Len() == 0 { + ruleRawList, ok := d.Get("rules").([]interface{}) + if !ok || len(ruleRawList) == 0 { return nil, errors.Errorf("rules is required") } ruleList := []*v1pb.SQLReviewRule{} - for _, r := range ruleSet.List() { + for _, r := range ruleRawList { rawRule := r.(map[string]interface{}) payload := rawRule["payload"].(string) if payload == "" { diff --git a/tutorials/0-provider.tf b/tutorials/0-provider.tf index f17221d..c5e8a52 100644 --- a/tutorials/0-provider.tf +++ b/tutorials/0-provider.tf @@ -1,7 +1,7 @@ terraform { required_providers { bytebase = { - version = "3.8.1" + version = "3.8.2" # For local development, please use "terraform.local/bytebase/bytebase" instead source = "registry.terraform.io/bytebase/bytebase" }