diff --git a/alicloud/resource_ram_policy.go b/alicloud/resource_ram_policy.go index 6ff00d1..caa3692 100644 --- a/alicloud/resource_ram_policy.go +++ b/alicloud/resource_ram_policy.go @@ -54,7 +54,11 @@ func (r *ramPolicyResource) Metadata(_ context.Context, req resource.MetadataReq func (r *ramPolicyResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Provides a RAM Policy resource that manages policy content exceeding character limits by splitting it into smaller segments. These segments are combined to form a complete policy attached to the user.", + Description: "Provides a RAM Policy resource that manages policy content " + + "exceeding character limits by splitting it into smaller segments. " + + "These segments are combined to form a complete policy attached to " + + "the user. However, the policy` that exceed the maximum length of a " + + "policy, they will be attached directly to the user.", Attributes: map[string]schema.Attribute{ "attached_policies": schema.ListAttribute{ Description: "The RAM policies to attach to the user.", @@ -362,7 +366,7 @@ func (r *ramPolicyResource) ImportState(ctx context.Context, req resource.Import } func (r *ramPolicyResource) createPolicy(plan *ramPolicyResourceModel) (policiesList []attr.Value, err error) { - formattedPolicy, err := r.getPolicyDocument(plan) + combinedPolicyStatements, notCombinedPolicies, err := r.getPolicyDocument(plan) if err != nil { return nil, err } @@ -370,7 +374,7 @@ func (r *ramPolicyResource) createPolicy(plan *ramPolicyResourceModel) (policies createPolicy := func() error { runtime := &util.RuntimeOptions{} - for i, policy := range formattedPolicy { + for i, policy := range combinedPolicyStatements { policyName := plan.UserName.ValueString() + "-" + strconv.Itoa(i+1) createPolicyRequest := &alicloudRamClient.CreatePolicyRequest{ @@ -386,7 +390,7 @@ func (r *ramPolicyResource) createPolicy(plan *ramPolicyResourceModel) (policies return nil } - for i, policies := range formattedPolicy { + for i, policies := range combinedPolicyStatements { policyName := plan.UserName.ValueString() + "-" + strconv.Itoa(i+1) policyObj := types.ObjectValueMust( @@ -402,6 +406,23 @@ func (r *ramPolicyResource) createPolicy(plan *ramPolicyResourceModel) (policies policiesList = append(policiesList, policyObj) } + // These policies will be attached directly to the user since splitting the + // policy "statement" will be hitting the limitation of "maximum number of + // attached policies" easily. + for _, policy := range notCombinedPolicies { + policyObj := types.ObjectValueMust( + map[string]attr.Type{ + "policy_name": types.StringType, + "policy_document": types.StringType, + }, + map[string]attr.Value{ + "policy_name": types.StringValue(policy.policyName), + "policy_document": types.StringValue(policy.policyDocument), + }, + ) + policiesList = append(policiesList, policyObj) + } + reconnectBackoff := backoff.NewExponentialBackOff() reconnectBackoff.MaxElapsedTime = 30 * time.Second return policiesList, backoff.Retry(createPolicy, reconnectBackoff) @@ -527,12 +548,16 @@ func (r *ramPolicyResource) removePolicy(state *ramPolicyResourceModel) diag.Dia return nil } -func (r *ramPolicyResource) getPolicyDocument(plan *ramPolicyResourceModel) (finalPolicyDocument []string, err error) { +type simplePolicy struct { + policyName string + policyDocument string +} + +func (r *ramPolicyResource) getPolicyDocument(plan *ramPolicyResourceModel) (finalPolicyDocument []string, excludedPolicy []simplePolicy, err error) { policyName := "" currentLength := 0 currentPolicyDocument := "" appendedPolicyDocument := make([]string, 0) - finalPolicyDocument = make([]string, 0) var getPolicyResponse *alicloudRamClient.GetPolicyResponse @@ -576,38 +601,52 @@ func (r *ramPolicyResource) getPolicyDocument(plan *ramPolicyResourceModel) (fin if getPolicyResponse.Body.DefaultPolicyVersion.PolicyDocument != nil { tempPolicyDocument := *getPolicyResponse.Body.DefaultPolicyVersion.PolicyDocument - var data map[string]interface{} - if err := json.Unmarshal([]byte(tempPolicyDocument), &data); err != nil { - return nil, err + skipCombinePolicy := false + // If the policy itself have more than 6144 characters, then skip the combine + // policy part since splitting the policy "statement" will be hitting the + // limitation of "maximum number of attached policies" easily. + if len(tempPolicyDocument) > maxLength { + excludedPolicy = append(excludedPolicy, simplePolicy{ + policyName: policyName, + policyDocument: tempPolicyDocument, + }) + skipCombinePolicy = true } - statementArr := data["Statement"].([]interface{}) - statementBytes, err := json.MarshalIndent(statementArr, "", " ") - if err != nil { - return nil, err - } + if !skipCombinePolicy { + var data map[string]interface{} + if err := json.Unmarshal([]byte(tempPolicyDocument), &data); err != nil { + return nil, nil, err + } - removeSpaces := strings.ReplaceAll(string(statementBytes), " ", "") - replacer := strings.NewReplacer("\n", "") - removeParagraphs := replacer.Replace(removeSpaces) + statementArr := data["Statement"].([]interface{}) + statementBytes, err := json.MarshalIndent(statementArr, "", " ") + if err != nil { + return nil, nil, err + } - finalStatement := strings.Trim(removeParagraphs, "[]") + removeSpaces := strings.ReplaceAll(string(statementBytes), " ", "") + replacer := strings.NewReplacer("\n", "") + removeParagraphs := replacer.Replace(removeSpaces) - currentLength += len(finalStatement) + finalStatement := strings.Trim(removeParagraphs, "[]") - // Before further proceeding the current policy, we need to add a number of 30 to simulate the total length of completed policy to check whether it is already execeeded the max character length of 6144. - // Number of 30 indicates the character length of neccessary policy keyword such as "Version" and "Statement" and some JSON symbols ({}, []) - if (currentLength + 30) > maxLength { - lastCommaIndex := strings.LastIndex(currentPolicyDocument, ",") - if lastCommaIndex >= 0 { - currentPolicyDocument = currentPolicyDocument[:lastCommaIndex] + currentPolicyDocument[lastCommaIndex+1:] - } + currentLength += len(finalStatement) - appendedPolicyDocument = append(appendedPolicyDocument, currentPolicyDocument) - currentPolicyDocument = finalStatement + "," - currentLength = len(finalStatement) - } else { - currentPolicyDocument += finalStatement + "," + // Before further proceeding the current policy, we need to add a number of 30 to simulate the total length of completed policy to check whether it is already execeeded the max character length of 6144. + // Number of 30 indicates the character length of neccessary policy keyword such as "Version" and "Statement" and some JSON symbols ({}, []) + if (currentLength + 30) > maxLength { + lastCommaIndex := strings.LastIndex(currentPolicyDocument, ",") + if lastCommaIndex >= 0 { + currentPolicyDocument = currentPolicyDocument[:lastCommaIndex] + currentPolicyDocument[lastCommaIndex+1:] + } + + appendedPolicyDocument = append(appendedPolicyDocument, currentPolicyDocument) + currentPolicyDocument = finalStatement + "," + currentLength = len(finalStatement) + } else { + currentPolicyDocument += finalStatement + "," + } } if i == len(plan.AttachedPolicies.Elements())-1 && (currentLength+30) <= maxLength { @@ -619,7 +658,7 @@ func (r *ramPolicyResource) getPolicyDocument(plan *ramPolicyResourceModel) (fin } } } else { - return nil, fmt.Errorf("could not find the policy: %v", policyName) + return nil, nil, fmt.Errorf("could not find the policy: %v", policyName) } } @@ -629,7 +668,7 @@ func (r *ramPolicyResource) getPolicyDocument(plan *ramPolicyResourceModel) (fin } } - return finalPolicyDocument, nil + return finalPolicyDocument, excludedPolicy, nil } func (r *ramPolicyResource) attachPolicyToUser(state *ramPolicyResourceModel) (err error) { diff --git a/docs/resources/ram_policy.md b/docs/resources/ram_policy.md index 6cee34c..f9f8489 100644 --- a/docs/resources/ram_policy.md +++ b/docs/resources/ram_policy.md @@ -3,12 +3,12 @@ page_title: "st-alicloud_ram_policy Resource - st-alicloud" subcategory: "" description: |- - Provides a RAM Policy resource that manages policy content exceeding character limits by splitting it into smaller segments. These segments are combined to form a complete policy attached to the user. + Provides a RAM Policy resource that manages policy content exceeding character limits by splitting it into smaller segments. These segments are combined to form a complete policy attached to the user. However, the policy that exceed the maximum length of a policy, they will be attached directly to the user. --- # st-alicloud_ram_policy (Resource) -Provides a RAM Policy resource that manages policy content exceeding character limits by splitting it into smaller segments. These segments are combined to form a complete policy attached to the user. +Provides a RAM Policy resource that manages policy content exceeding character limits by splitting it into smaller segments. These segments are combined to form a complete policy attached to the user. However, the policy that exceed the maximum length of a policy, they will be attached directly to the user. ## Example Usage