From 6b10ef53c01589c9f42953006daf3d6e09aa8831 Mon Sep 17 00:00:00 2001 From: Jason-Zhang Date: Fri, 14 Jun 2024 16:20:13 +0800 Subject: [PATCH] refactor(cdn): make ForceNew of name configurable (#4632) --- docs/resources/cdn_domain.md | 2 +- huaweicloud/config/config.go | 18 ++++++ huaweicloud/config/force_new.go | 61 +++++++++++++++++++ huaweicloud/provider.go | 10 +++ .../cdn/resource_huaweicloud_cdn_domain.go | 15 +++-- huaweicloud/utils/utils.go | 8 --- 6 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 huaweicloud/config/force_new.go diff --git a/docs/resources/cdn_domain.md b/docs/resources/cdn_domain.md index 1e70aa0fb1..699d366596 100644 --- a/docs/resources/cdn_domain.md +++ b/docs/resources/cdn_domain.md @@ -205,7 +205,7 @@ resource "huaweicloud_cdn_domain" "domain_1" { The following arguments are supported: -* `name` - (Required, String) Specifies acceleration domain name. The domain name consists of one or more parts, +* `name` - (Required, String, NonUpdatable) Specifies acceleration domain name. The domain name consists of one or more parts, representing domains at different levels. Domain names at all levels can only be composed of letters, digits, and hyphens (-), and the letters are equivalent in upper and lower case. Domain names at all levels are connected with (.). The domain name can contain up to `75` characters. diff --git a/huaweicloud/config/config.go b/huaweicloud/config/config.go index a75720c61c..a323a2475a 100644 --- a/huaweicloud/config/config.go +++ b/huaweicloud/config/config.go @@ -7,6 +7,7 @@ import ( "log" "math" "os" + "strconv" "strings" "sync" "time" @@ -93,6 +94,8 @@ type Config struct { // Metadata is used for extend Metadata any + + EnableForceNew bool } func (c *Config) LoadAndValidate() error { @@ -589,6 +592,21 @@ func CheckValueInterchange(d *schema.ResourceDiff, key1, key2 string) (isKey1New return isKey1NewEqualKey2Old, isKey2NewEqualKey1Old } +// GetForceNew returns the enable_force_new that was specified in the resource. +// If it was not set, the provider-level value is checked. The provider-level value can +// either be set by the `enable_force_new` argument or by HW_ENABLE_FORCE_NEW. +func (c *Config) GetForceNew(d *schema.ResourceDiff) bool { + if v, ok := d.GetOk("enable_force_new"); ok { + res, err := strconv.ParseBool(v.(string)) + if err != nil { + return false + } + return res + } + + return c.EnableForceNew +} + // ********** client for Global Service ********** func (c *Config) IAMV3Client(region string) (*golangsdk.ServiceClient, error) { return c.NewServiceClient("iam", region) diff --git a/huaweicloud/config/force_new.go b/huaweicloud/config/force_new.go new file mode 100644 index 0000000000..fa9a3a9570 --- /dev/null +++ b/huaweicloud/config/force_new.go @@ -0,0 +1,61 @@ +package config + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// FlexibleForceNew make the ForceNew of parameters configurable +// this func accepts a list of non-updatable parameters +// when non-updatable parameters are changed +// if ForceNew is enabled, the resource will be recreated +// if ForceNew is not enabled, an error will be raise +func FlexibleForceNew(keys []string) schema.CustomizeDiffFunc { + return func(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + cfg := meta.(*Config) + var err error + forceNew := cfg.GetForceNew(d) + keysExpand := expandKeys(keys, d) + if forceNew { + for _, k := range keysExpand { + if err := d.ForceNew(k); err != nil { + log.Printf("[WARN] unable to require attribute replacement of %s: %s", k, err) + } + } + } else { + for _, k := range keysExpand { + if d.Id() != "" && d.HasChange(k) { + err = multierror.Append(err, fmt.Errorf("%s can't be updated", k)) + } + } + } + + return err + } +} + +func expandKeys(keys []string, d *schema.ResourceDiff) []string { + res := []string{} + for _, k := range keys { + if strings.Contains(k, "*") { + parts := strings.SplitN(k, ".*.", 2) + l := len(d.Get(parts[0]).([]interface{})) + i := 0 + var tempKeys []string + for i < l { + tempKeys = append(tempKeys, strings.Join([]string{parts[0], parts[1]}, fmt.Sprintf(".%s.", strconv.Itoa(i)))) + i++ + } + res = append(res, expandKeys(tempKeys, d)...) + } else { + res = append(res, k) + } + } + return res +} diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index a778464ccb..ffac569631 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -400,6 +400,13 @@ func Provider() *schema.Provider { Description: descriptions["max_retries"], DefaultFunc: schema.EnvDefaultFunc("HW_MAX_RETRIES", 5), }, + + "enable_force_new": { + Type: schema.TypeBool, + Optional: true, + Description: descriptions["enable_force_new"], + DefaultFunc: schema.EnvDefaultFunc("HW_ENABLE_FORCE_NEW", false), + }, }, DataSourcesMap: map[string]*schema.Resource{ @@ -1955,6 +1962,8 @@ func init() { "max_retries": "How many times HTTP connection should be retried until giving up.", "enterprise_project_id": "enterprise project id", + + "enable_force_new": "Whether to enable ForceNew", } } @@ -1986,6 +1995,7 @@ func configureProvider(_ context.Context, d *schema.ResourceData, terraformVersi RegionProjectIDMap: make(map[string]string), RPLock: new(sync.Mutex), SecurityKeyLock: new(sync.Mutex), + EnableForceNew: d.Get("enable_force_new").(bool), } // get assume role diff --git a/huaweicloud/services/cdn/resource_huaweicloud_cdn_domain.go b/huaweicloud/services/cdn/resource_huaweicloud_cdn_domain.go index fd53a25784..0b065b4d9d 100644 --- a/huaweicloud/services/cdn/resource_huaweicloud_cdn_domain.go +++ b/huaweicloud/services/cdn/resource_huaweicloud_cdn_domain.go @@ -26,6 +26,8 @@ import ( "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" ) +var nonUpdatableParams = []string{"name"} + var httpsConfig = schema.Schema{ Type: schema.TypeList, Optional: true, @@ -779,11 +781,12 @@ func ResourceCdnDomain() *schema.Resource { Delete: schema.DefaultTimeout(20 * time.Minute), }, + CustomizeDiff: config.FlexibleForceNew(nonUpdatableParams), + Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, Required: true, - ForceNew: utils.GetForceNew(), }, "type": { Type: schema.TypeString, @@ -997,6 +1000,12 @@ func ResourceCdnDomain() *schema.Resource { }, }, "tags": common.TagsSchema(), + "enable_force_new": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"true", "false"}, false), + Description: utils.SchemaDesc("", utils.SchemaDescInput{Internal: true}), + }, "cname": { Type: schema.TypeString, Computed: true, @@ -2420,10 +2429,6 @@ func parseDetailResponseError(err error) error { } func resourceCdnDomainUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - if d.HasChange("name") && !d.IsNewResource() { - return diag.Errorf("error updating CDN domain name: not supported!") - } - cfg := meta.(*config.Config) region := cfg.GetRegion(d) hcCdnClient, err := cfg.HcCdnV2Client(region) diff --git a/huaweicloud/utils/utils.go b/huaweicloud/utils/utils.go index 0ccb4d8bb0..5d571b98cd 100644 --- a/huaweicloud/utils/utils.go +++ b/huaweicloud/utils/utils.go @@ -556,11 +556,3 @@ func IsUUID(uuid string) bool { match, _ := regexp.MatchString(pattern, uuid) return match } - -func GetForceNew() bool { - forceNew, err := strconv.ParseBool(os.Getenv("HW_ENABLE_FORCE_NEW")) - if err != nil { - return false - } - return forceNew -}