From 78230d9420620e766c6ac351d954c7f44d570423 Mon Sep 17 00:00:00 2001 From: Artem Lifshits <55093318+artem-lifshits@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:36:16 +0100 Subject: [PATCH] RMS: policy assignment&definition (#2701) RMS: policy assignment&definition Summary of the Pull Request Policy assignment resource Policy definition data source PR Checklist Refers to: #2659 Tests added/passed. Documentation updated. Schema updated. Release notes added. Acceptance Steps Performed 2024/10/30 20:32:08 [INFO] Building Swift S3 auth structure 2024/10/30 20:32:08 [INFO] Setting AWS metadata API timeout to 100ms 2024/10/30 20:32:10 [INFO] Ignoring AWS metadata API endpoint at default location as it doesn't return any instance-id 2024/10/30 20:32:10 [INFO] Swift S3 Auth provider used: "StaticProvider" === RUN TestAccPolicyAssignment_custom === PAUSE TestAccPolicyAssignment_custom === CONT TestAccPolicyAssignment_custom --- PASS: TestAccPolicyAssignment_custom (439.98s) PASS Process finished with the exit code 0 2024/10/30 20:40:31 [INFO] Building Swift S3 auth structure 2024/10/30 20:40:31 [INFO] Setting AWS metadata API timeout to 100ms 2024/10/30 20:40:33 [INFO] Ignoring AWS metadata API endpoint at default location as it doesn't return any instance-id 2024/10/30 20:40:33 [INFO] Swift S3 Auth provider used: "StaticProvider" === RUN TestAccPolicyAssignment_basic === PAUSE TestAccPolicyAssignment_basic === CONT TestAccPolicyAssignment_basic --- PASS: TestAccPolicyAssignment_basic (491.21s) PASS Process finished with the exit code 0 Reviewed-by: Anton Sidelnikov --- .../data-sources/rms_policy_definitions_v1.md | 72 +++ docs/resources/rms_policy_assignment_v1.md | 173 ++++++ ...ekomcloud_rms_policy_assignment_v1_test.go | 342 +++++++++++ opentelekomcloud/common/utils.go | 14 + opentelekomcloud/provider.go | 2 + opentelekomcloud/services/dms/common.go | 16 - .../data_source_opentelekomcloud_flavor_v2.go | 2 +- ...ntelekomcloud_rms_policy_definitions_v1.go | 200 +++++++ ...entelekomcloud_rms_policy_assignment_v1.go | 536 ++++++++++++++++++ .../notes/rms_policies-0f92edd815065b57.yaml | 6 + 10 files changed, 1346 insertions(+), 17 deletions(-) create mode 100644 docs/data-sources/rms_policy_definitions_v1.md create mode 100644 docs/resources/rms_policy_assignment_v1.md create mode 100644 opentelekomcloud/acceptance/rms/resource_opentelekomcloud_rms_policy_assignment_v1_test.go create mode 100644 opentelekomcloud/services/rms/data_opentelekomcloud_rms_policy_definitions_v1.go create mode 100644 opentelekomcloud/services/rms/resource_opentelekomcloud_rms_policy_assignment_v1.go create mode 100644 releasenotes/notes/rms_policies-0f92edd815065b57.yaml diff --git a/docs/data-sources/rms_policy_definitions_v1.md b/docs/data-sources/rms_policy_definitions_v1.md new file mode 100644 index 000000000..dcb58c19a --- /dev/null +++ b/docs/data-sources/rms_policy_definitions_v1.md @@ -0,0 +1,72 @@ +--- +subcategory: "Config" +layout: "opentelekomcloud" +page_title: "OpenTelekomCloud: opentelekomcloud_rms_policy_definitions_v1" +sidebar_current: "docs-opentelekomcloud-datasource-rms-policy-definitions-v1" +description: |- + Manages an RMS Policy Definitions data source within OpenTelekomCloud. +--- + +Up-to-date reference of API arguments for RMS Policy Definitions you can get at +[documentation portal](https://docs.otc.t-systems.com/config/api-ref/apis/compliance/querying_all_built-in_policies.html#rms-04-0501) + + +# opentelekomcloud_rms_policy_definitions_v1 + +Use this data source to query policy definition list. + +## Example Usage + +```hcl +variable "trigger_type" {} + +data "opentelekomcloud_rms_policy_definitions_v1" "test" { + trigger_type = var.trigger_type +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional, String) Specifies the name of the policy definitions used to query definition list. + +* `policy_type` - (Optional, String) Specifies the policy type used to query definition list. + The valid value is **builtin**. + +* `policy_rule_type` - (Optional, String) Specifies the policy rule type used to query definition list. + +* `trigger_type` - (Optional, String) Specifies the trigger type used to query definition list. + The valid values are **resource** and **period**. + +* `keywords` - (Optional, List) Specifies the keyword list used to query definition list. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `definitions` - The policy definition list. + The [object](#policy_definitions) structure is documented below. + + +The `definitions` block supports: + +* `id` - The ID of the policy definition. + +* `name` - The name of the policy definition. + +* `policy_type` - The policy type of the policy definition. + +* `description` - The description of the policy definition. + +* `policy_rule_type` - The policy rule type of the policy definition. + +* `policy_rule` - The policy rule of the policy definition. + +* `trigger_type` - The trigger type of the policy definition. + +* `keywords` - The keyword list of the policy definition. + +* `parameters` - The parameter reference map of the policy definition. diff --git a/docs/resources/rms_policy_assignment_v1.md b/docs/resources/rms_policy_assignment_v1.md new file mode 100644 index 000000000..128dd7e13 --- /dev/null +++ b/docs/resources/rms_policy_assignment_v1.md @@ -0,0 +1,173 @@ +--- +subcategory: "Config" +layout: "opentelekomcloud" +page_title: "OpenTelekomCloud: opentelekomcloud_rms_policy_assignment_v1" +sidebar_current: "docs-opentelekomcloud-rms-policy-assignment-v1" +description: |- + Manages an RMS Policy Assignment resource within OpenTelekomCloud. +--- + +Up-to-date reference of API arguments for RMS Policy Assignment you can get at +[documentation portal](https://docs.otc.t-systems.com/config/api-ref/apis/compliance/index.html) + +# opentelekomcloud_rms_policy_assignment_v1 + +Using this resource to assign the policy and evaluate OpenTelekomCloud resources. + +## Example Usage + +### Assign a built-in policy to check a specified instance by a flavor + +```hcl +variable "policy_assignment_name" {} +variable "region_name" {} +variable "ecs_instance_id" {} +variable "compliant_flavor" {} + +data "opentelekomcloud_rms_policy_definitions_v1" "test" { + name = "allowed-ecs-flavors" +} + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = var.policy_assignment_name + description = "An ECS is noncompliant if its flavor is not in the specified flavor list (filter by resource ID)." + policy_definition_id = try(data.opentelekomcloud_rms_policy_definitions_v1.test.definitions[0].id, "") + status = "Enabled" + + policy_filter { + region = var.region_name + resource_provider = "ecs" + resource_type = "cloudservers" + resource_id = var.ecs_instance_id + } + + parameters = { + listOfAllowedFlavors = "[\"${var.compliant_flavor}\"]" + } +} +``` + +### Assign a custom policy + +```hcl +variable "policy_assignment_name" {} +variable "function_urn" {} +variable "function_version" {} +variable "rms_admin_trust_agency" {} + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = var.policy_assignment_name + description = "The ECS instances that do not conform to the custom function logic are considered non-compliant." + status = "Enabled" + + custom_policy { + function_urn = "${var.function_urn}:${var.function_version}" + auth_type = "agency" + auth_value = { + agency_name = "\"${var.rms_admin_trust_agency}\"" + } + } + + parameters = { + string_example = "\"string_value\"" + array_example = "[\"array_element\"]" + object_example = "{\"terraform_version\":\"1.xx.x\"}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required, String, ForceNew) Specifies the name of the policy assignment. + The valid length is limited from `1` to `64`. + Change this parameter will create a new resource. + +* `description` - (Optional, String) Specifies the description of the policy assignment, which contain maximum of + `512` characters. + +* `policy_definition_id` - (Optional, String) Specifies the ID of the built-in policy definition. + This parameter and `custom_policy` are alternative. + +* `period` - (Optional, String) Specifies the period of the policy assignment. + The valid values are as follows: + + **One_Hour** + + **Three_Hours** + + **Six_Hours** + + **Twelve_Hours** + + **TwentyFour_Hours** + + Most one of `period` and `policy_filter` can be configured. + +* `policy_filter` - (Optional, List) Specifies the configuration used to filter resources. + The [object](#rms_policy_filter) structure is documented below. + +-> If the `period` is configured, it means that the evaluation is performed periodically. + If the `policy_filter` is configured, it means that the evaluation is performed on the specified resources through + the filter. If neither parameter is configured, it means that the evaluation is performed on all resources under the + account. + +* `custom_policy` - (Optional, List) Specifies the configuration of the custom policy. + The [object](#rms_custom_policy) structure is documented below. + +* `parameters` - (Optional, Map) Specifies the rule definition of the policy assignment. + +* `status` - (Optional, String) Specifies the expect status of the policy. + The valid values are **Enabled** and **Disabled**. + + +The `policy_filter` block supports: + +* `region` - (Optional, String) Specifies the name of the region to which the filtered resources belong. + +* `resource_provider` - (Optional, String) Specifies the service name to which the filtered resources belong. + +* `resource_type` - (Optional, String) Specifies the resource type of the filtered resources. + +* `resource_id` - (Optional, String) Specifies the resource ID used to filter a specified resource. + +* `tag_key` - (Optional, String) Specifies the tag name used to filter resources. + This parameter and `resource_id` are alternative. + +* `tag_value` - (Optional, String) Specifies the tag value used to filter resources. + Required if `tag_key` is set. + + +The `custom_policy` block supports: + +* `function_urn` - (Required, String) Specifies the function URN used to create the custom policy. + +* `auth_type` - (Required, String) Specifies the authorization type of the custom policy. + +* `auth_value` - (Optional, Map) Specifies the authorization value of the custom policy. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the policy assignment. + +* `type` - The type of the policy assignment. + The valid values are as follows: + + **builtin** + + **custom** + +* `created_at` - The creation time of the policy assignment. + +* `updated_at` - The latest update time of the policy assignment. + +## Timeouts + +This resource provides the following timeouts configuration options: + +* `create` - Default is 5 minutes. +* `update` - Default is 5 minutes. + +## Import + +Policy assignments can be imported using their `id`, e.g. + +```bash +$ terraform import opentelekomcloud_rms_policy_assignment_v1.test 63f48e3762ce955981ab7e25 +``` diff --git a/opentelekomcloud/acceptance/rms/resource_opentelekomcloud_rms_policy_assignment_v1_test.go b/opentelekomcloud/acceptance/rms/resource_opentelekomcloud_rms_policy_assignment_v1_test.go new file mode 100644 index 000000000..432acd557 --- /dev/null +++ b/opentelekomcloud/acceptance/rms/resource_opentelekomcloud_rms_policy_assignment_v1_test.go @@ -0,0 +1,342 @@ +package rms + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/rms/compliance" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/acceptance/common" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/acceptance/env" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/cfg" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/services/rms" +) + +var ( + statusReg = regexp.MustCompile(`^(Enabled|Evaluating)$`) +) + +func getPolicyAssignmentResourceFunc(conf *cfg.Config, state *terraform.ResourceState) (interface{}, error) { + client, err := conf.RmsV1Client(env.OS_REGION_NAME) + if err != nil { + return nil, fmt.Errorf("error creating RMS V1 client: %s", err) + } + + domainId := rms.GetRmsDomainId(client, conf) + + return compliance.GetRule(client, domainId, state.Primary.ID) +} + +func TestAccPolicyAssignment_basic(t *testing.T) { + var ( + obj compliance.PolicyRule + + rName = "opentelekomcloud_rms_policy_assignment_v1.test" + name = "rms-test" + acctest.RandString(5) + basicConfig = testAccPolicyAssignment_ecsConfig(name) + ) + + rc := common.InitResourceCheck( + rName, + &obj, + getPolicyAssignmentResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + common.TestAccPreCheck(t) + }, + ProviderFactories: common.TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccPolicyAssignment_basic(basicConfig, name, "Disabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "type", rms.AssignmentTypeBuiltin), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttrPair(rName, "policy_definition_id", + "data.opentelekomcloud_rms_policy_definitions_v1.test", "definitions.0.id"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.region", env.OS_REGION_NAME), + resource.TestCheckResourceAttr(rName, "policy_filter.0.resource_provider", "ecs"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.resource_type", "cloudservers"), + resource.TestCheckResourceAttrPair(rName, "policy_filter.0.resource_id", + "opentelekomcloud_compute_instance_v2.test", "id"), + resource.TestCheckResourceAttr(rName, "status", "Disabled"), + resource.TestCheckResourceAttrSet(rName, "parameters.listOfAllowedFlavors"), + resource.TestCheckResourceAttrSet(rName, "created_at"), + resource.TestCheckResourceAttrSet(rName, "updated_at"), + ), + }, + { + Config: testAccPolicyAssignment_basic(basicConfig, name, "Enabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestMatchResourceAttr(rName, "status", statusReg), + ), + }, + { + Config: testAccPolicyAssignment_basicUpdate(basicConfig, name, "Enabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "type", rms.AssignmentTypeBuiltin), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttrPair(rName, "policy_definition_id", + "data.opentelekomcloud_rms_policy_definitions_v1.test", "definitions.0.id"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.region", env.OS_REGION_NAME), + resource.TestCheckResourceAttr(rName, "policy_filter.0.resource_provider", "ecs"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.resource_type", "cloudservers"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.tag_key", "foo"), + resource.TestCheckResourceAttr(rName, "policy_filter.0.tag_value", "bar"), + resource.TestMatchResourceAttr(rName, "status", statusReg), + resource.TestCheckResourceAttrSet(rName, "parameters.listOfAllowedFlavors"), + resource.TestCheckResourceAttrSet(rName, "created_at"), + resource.TestCheckResourceAttrSet(rName, "updated_at"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccPolicyAssignment_ecsConfig(name string) string { + return fmt.Sprintf(` + + +resource "opentelekomcloud_vpc_v1" "test" { + name = "%[1]s" + cidr = "192.168.0.0/16" +} + +resource "opentelekomcloud_vpc_subnet_v1" "test" { + name = "%[1]s" + vpc_id = opentelekomcloud_vpc_v1.test.id + cidr = cidrsubnet(opentelekomcloud_vpc_v1.test.cidr, 4, 1) + gateway_ip = cidrhost(cidrsubnet(opentelekomcloud_vpc_v1.test.cidr, 4, 1), 1) +} + +resource "opentelekomcloud_networking_secgroup_v2" "test" { + name = "%[1]s" + delete_default_rules = true +} + +resource "opentelekomcloud_compute_instance_v2" "test" { + name = "%[1]s" + image_name = "Standard_Debian_11_latest" + flavor_name = "s3.large.2" + security_groups = [opentelekomcloud_networking_secgroup_v2.test.name] + availability_zone = "eu-de-01" + + network { + uuid = opentelekomcloud_vpc_subnet_v1.test.id + } +} +`, name) +} + +func testAccPolicyAssignment_basic(basicConfig, name, status string) string { + return fmt.Sprintf(` +%[1]s + +data "opentelekomcloud_compute_flavor_v2" "test" { + name = "s3.large.2" +} + +data "opentelekomcloud_rms_policy_definitions_v1" "test" { + name = "allowed-ecs-flavors" +} + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = "%[2]s" + description = "Test description" + policy_definition_id = try(data.opentelekomcloud_rms_policy_definitions_v1.test.definitions[0].id, "") + status = "%[3]s" + + policy_filter { + region = "%[4]s" + resource_provider = "ecs" + resource_type = "cloudservers" + resource_id = opentelekomcloud_compute_instance_v2.test.id + } + + parameters = { + listOfAllowedFlavors = "[\"${data.opentelekomcloud_compute_flavor_v2.test.id}\"]" + } +} +`, basicConfig, name, status, env.OS_REGION_NAME) +} + +func testAccPolicyAssignment_basicUpdate(basicConfig, name, status string) string { + return fmt.Sprintf(` +%[1]s + +data "opentelekomcloud_compute_flavor_v2" "test" { + name = "s3.large.2" +} + +data "opentelekomcloud_rms_policy_definitions_v1" "test" { + name = "allowed-ecs-flavors" +} + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = "%[2]s" + description = "Test description" + policy_definition_id = try(data.opentelekomcloud_rms_policy_definitions_v1.test.definitions[0].id, "") + status = "%[3]s" + + policy_filter { + region = "%[4]s" + resource_provider = "ecs" + resource_type = "cloudservers" + tag_key = "foo" + tag_value = "bar" + } + + parameters = { + listOfAllowedFlavors = "[\"${data.opentelekomcloud_compute_flavor_v2.test.id}\"]" + } +} +`, basicConfig, name, status, env.OS_REGION_NAME) +} + +func TestAccPolicyAssignment_custom(t *testing.T) { + var ( + obj compliance.PolicyRule + + rName = "opentelekomcloud_rms_policy_assignment_v1.test" + name = "rms-test-" + acctest.RandString(5) + customConfig = testAccPolicyAssignment_customConfig(name) + ) + + rc := common.InitResourceCheck( + rName, + &obj, + getPolicyAssignmentResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + common.TestAccPreCheck(t) + }, + ProviderFactories: common.TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccPolicyAssignment_custom(customConfig, name, "Disabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "type", rms.AssignmentTypeCustom), + resource.TestCheckResourceAttr(rName, "description", "Test description"), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttr(rName, "status", "Disabled"), + resource.TestCheckResourceAttr(rName, "parameters.string_test", "\"string_value\""), + resource.TestCheckResourceAttr(rName, "parameters.array_test", "[\"array_element\"]"), + resource.TestCheckResourceAttr(rName, "parameters.object_test", "{\"terraform_version\":\"1.xx.x\"}"), + resource.TestCheckResourceAttrSet(rName, "created_at"), + resource.TestCheckResourceAttrSet(rName, "updated_at"), + ), + }, + { + Config: testAccPolicyAssignment_custom(customConfig, name, "Enabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestMatchResourceAttr(rName, "status", statusReg), + ), + }, + { + Config: testAccPolicyAssignment_customUpdate(customConfig, name, "Enabled"), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttr(rName, "parameters.string_test", "\"update_string_value\""), + resource.TestCheckResourceAttr(rName, "parameters.update_array_test", "[\"array_element\"]"), + resource.TestCheckResourceAttr(rName, "parameters.object_test", "{\"update_terraform_version\":\"1.xx.xx\"}"), + resource.TestMatchResourceAttr(rName, "status", statusReg), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccPolicyAssignment_customConfig(name string) string { + customConfig := testAccPolicyAssignment_ecsConfig(name) + + return fmt.Sprintf(` +%[1]s + +resource "opentelekomcloud_fgs_function_v2" "test" { + name = "%[2]s" + code_type = "inline" + handler = "index.handler" + runtime = "Node.js10.16" + functiongraph_version = "v2" + app = "default" + memory_size = 128 + timeout = 3 +} +`, customConfig, name) +} + +func testAccPolicyAssignment_custom(customConfig, name, status string) string { + return fmt.Sprintf(` +%[1]s + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = "%[2]s" + description = "Test description" + status = "%[3]s" + + custom_policy { + function_urn = "${opentelekomcloud_fgs_function_v2.test.urn}:${opentelekomcloud_fgs_function_v2.test.version}" + auth_type = "agency" + auth_value = { + agency_name = "\"rms_tracker_agency\"" + } + } + + parameters = { + string_test = "\"string_value\"" + array_test = "[\"array_element\"]" + object_test = "{\"terraform_version\":\"1.xx.x\"}" + } +} +`, customConfig, name, status) +} + +func testAccPolicyAssignment_customUpdate(customConfig, name, status string) string { + return fmt.Sprintf(` +%[1]s + +resource "opentelekomcloud_rms_policy_assignment_v1" "test" { + name = "%[2]s" + description = "Test description" + status = "%[3]s" + + custom_policy { + function_urn = "${opentelekomcloud_fgs_function_v2.test.urn}:${opentelekomcloud_fgs_function_v2.test.version}" + auth_type = "agency" + auth_value = { + agency_name = "\"rms_tracker_agency\"" + } + } + + parameters = { + string_test = "\"update_string_value\"" + update_array_test = "[\"array_element\"]" + object_test = "{\"update_terraform_version\":\"1.xx.xx\"}" + } +} +`, customConfig, name, status) +} diff --git a/opentelekomcloud/common/utils.go b/opentelekomcloud/common/utils.go index 603bc1595..c9b22ac91 100644 --- a/opentelekomcloud/common/utils.go +++ b/opentelekomcloud/common/utils.go @@ -547,3 +547,17 @@ func hasMapContain(rawMap map[string]string, filterKey, filterValue string) bool return false } } + +// StrSliceContainsAnother checks whether a string slice (b) contains another string slice (s). +func StrSliceContainsAnother(b []string, s []string) bool { + // The empty set is the subset of any set. + if len(s) < 1 { + return true + } + for _, v := range s { + if !StrSliceContains(b, v) { + return false + } + } + return true +} diff --git a/opentelekomcloud/provider.go b/opentelekomcloud/provider.go index 4a94d6b26..6851991d0 100644 --- a/opentelekomcloud/provider.go +++ b/opentelekomcloud/provider.go @@ -330,6 +330,7 @@ func Provider() *schema.Provider { "opentelekomcloud_rds_flavors_v1": rds.DataSourceRdsFlavorV1(), "opentelekomcloud_rds_flavors_v3": rds.DataSourceRdsFlavorV3(), "opentelekomcloud_rds_versions_v3": rds.DataSourceRdsVersionsV3(), + "opentelekomcloud_rms_policy_definitions_v1": rms.DataSourcePolicyDefinitions(), "opentelekomcloud_rts_software_deployment_v1": rts.DataSourceRtsSoftwareDeploymentV1(), "opentelekomcloud_rts_software_config_v1": rts.DataSourceRtsSoftwareConfigV1(), "opentelekomcloud_rts_stack_resource_v1": rts.DataSourceRTSStackResourcesV1(), @@ -528,6 +529,7 @@ func Provider() *schema.Provider { "opentelekomcloud_rds_read_replica_v3": rds.ResourceRdsReadReplicaV3(), "opentelekomcloud_rms_advanced_query_v1": rms.ResourceRmsAdvancedQueryV1(), "opentelekomcloud_rms_resource_recorder_v1": rms.ResourceRmsResourceRecorderV1(), + "opentelekomcloud_rms_policy_assignment_v1": rms.ResourceRmsPolicyAssignmentV1(), "opentelekomcloud_rts_software_deployment_v1": rts.ResourceRtsSoftwareDeploymentV1(), "opentelekomcloud_rts_software_config_v1": rts.ResourceSoftwareConfigV1(), "opentelekomcloud_rts_stack_v1": rts.ResourceRTSStackV1(), diff --git a/opentelekomcloud/services/dms/common.go b/opentelekomcloud/services/dms/common.go index 73e799083..0d39a25cb 100644 --- a/opentelekomcloud/services/dms/common.go +++ b/opentelekomcloud/services/dms/common.go @@ -4,8 +4,6 @@ import ( "encoding/json" "log" "strings" - - "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common" ) const ( @@ -27,17 +25,3 @@ func MarshalValue(i interface{}) string { return strings.Trim(string(jsonRaw), `"`) } - -// StrSliceContainsAnother checks whether a string slice (b) contains another string slice (s). -func StrSliceContainsAnother(b []string, s []string) bool { - // The empty set is the subset of any set. - if len(s) < 1 { - return true - } - for _, v := range s { - if !common.StrSliceContains(b, v) { - return false - } - } - return true -} diff --git a/opentelekomcloud/services/dms/data_source_opentelekomcloud_flavor_v2.go b/opentelekomcloud/services/dms/data_source_opentelekomcloud_flavor_v2.go index 91b931e09..784f1e245 100644 --- a/opentelekomcloud/services/dms/data_source_opentelekomcloud_flavor_v2.go +++ b/opentelekomcloud/services/dms/data_source_opentelekomcloud_flavor_v2.go @@ -263,7 +263,7 @@ func filterFlavors(d *schema.ResourceData, flavorList []products.EngineProduct) if scOk && io.IOSpec != sc.(string) { continue } - if StrSliceContainsAnother(io.AvailableZones, common.ExpandToStringList(azs)) { + if common.StrSliceContainsAnother(io.AvailableZones, common.ExpandToStringList(azs)) { validIOs = append(validIOs, io) } } diff --git a/opentelekomcloud/services/rms/data_opentelekomcloud_rms_policy_definitions_v1.go b/opentelekomcloud/services/rms/data_opentelekomcloud_rms_policy_definitions_v1.go new file mode 100644 index 000000000..bcdba5b21 --- /dev/null +++ b/opentelekomcloud/services/rms/data_opentelekomcloud_rms_policy_definitions_v1.go @@ -0,0 +1,200 @@ +package rms + +import ( + "context" + "encoding/json" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/rms/compliance" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/cfg" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/fmterr" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/helper/hashcode" +) + +func DataSourcePolicyDefinitions() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourcePolicyDefinitionsRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + }, + "policy_type": { + Type: schema.TypeString, + Optional: true, + }, + "policy_rule_type": { + Type: schema.TypeString, + Optional: true, + }, + "trigger_type": { + Type: schema.TypeString, + Optional: true, + }, + "keywords": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "definitions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "policy_type": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "policy_rule_type": { + Type: schema.TypeString, + Computed: true, + }, + "policy_rule": { + Type: schema.TypeString, + Computed: true, + }, + "trigger_type": { + Type: schema.TypeString, + Computed: true, + }, + "keywords": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "parameters": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + } +} + +func filterPolicyDefinitionsByKeywords(definitions []compliance.PolicyDefinition, + keywords []interface{}) []compliance.PolicyDefinition { + if len(keywords) < 1 { + return definitions + } + + filter := common.ExpandToStringList(keywords) + result := make([]compliance.PolicyDefinition, 0, len(definitions)) + for _, v := range definitions { + if common.StrSliceContainsAnother(v.Keywords, filter) { + result = append(result, v) + } + } + return result +} + +func flattenDefinitionParameters(parameters map[string]compliance.PolicyParameterDefinition) ( + map[string]interface{}, error) { + if len(parameters) < 1 { + return nil, nil + } + + result := make(map[string]interface{}) + for k, v := range parameters { + jsonBytes, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("generate json string failed: %s", err) + } + result[k] = string(jsonBytes) + } + return result, nil +} + +func filterPolicyDefinitions(definitions []compliance.PolicyDefinition, + d *schema.ResourceData) ([]map[string]interface{}, []string, error) { + filter := map[string]interface{}{ + "Name": d.Get("name"), + "PolicyType": d.Get("policy_type"), + "PolicyRuleType": d.Get("policy_rule_type"), + "TriggerType": d.Get("trigger_type"), + } + filtResult, err := common.FilterSliceWithField(definitions, filter) + if err != nil { + return nil, nil, fmt.Errorf("filter component runtimes failed: %s", err) + } + log.Printf("[DEBUG] Filter %d policy definitions from server through options: %v", len(filtResult), filter) + + result := make([]map[string]interface{}, len(filtResult)) + ids := make([]string, len(filtResult)) + for i, val := range filtResult { + definition := val.(compliance.PolicyDefinition) + ids[i] = definition.ID + dm := map[string]interface{}{ + "id": definition.ID, + "name": definition.Name, + "policy_type": definition.PolicyType, + "description": definition.Description, + "policy_rule_type": definition.PolicyRuleType, + "policy_rule": definition.PolicyRule, + "trigger_type": definition.TriggerType, + "keywords": definition.Keywords, + } + + params, err := flattenDefinitionParameters(definition.Parameters) + if err != nil { + return nil, nil, fmt.Errorf("failed to flatten definition parameters: %s", err) + } + dm["parameters"] = params + + jsonBytes, err := json.Marshal(definition.PolicyRule) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate json string: %s", err) + } + dm["policy_rule"] = string(jsonBytes) + + result[i] = dm + } + return result, ids, nil +} + +func dataSourcePolicyDefinitionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*cfg.Config) + client, err := common.ClientFromCtx(ctx, rmsClientV1, func() (*golangsdk.ServiceClient, error) { + return config.RmsV1Client(config.GetRegion(d)) + }) + if err != nil { + return fmterr.Errorf(errCreationRMSV1Client, err) + } + + definitions, err := compliance.ListAllPolicies(client) + if err != nil { + return diag.Errorf("error getting the policy definition list form server: %s", err) + } + + filterResult := filterPolicyDefinitionsByKeywords(definitions, d.Get("keywords").([]interface{})) + dm, ids, err := filterPolicyDefinitions(filterResult, d) + if err != nil { + return diag.Errorf("error query policy definitions: %s", err) + } + d.SetId(hashcode.Strings(ids)) + + if err = d.Set("definitions", dm); err != nil { + return diag.Errorf("error saving the information of the policy definitions to state: %s", err) + } + return nil +} diff --git a/opentelekomcloud/services/rms/resource_opentelekomcloud_rms_policy_assignment_v1.go b/opentelekomcloud/services/rms/resource_opentelekomcloud_rms_policy_assignment_v1.go new file mode 100644 index 000000000..871b38ec3 --- /dev/null +++ b/opentelekomcloud/services/rms/resource_opentelekomcloud_rms_policy_assignment_v1.go @@ -0,0 +1,536 @@ +package rms + +import ( + "context" + "encoding/json" + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/rms/compliance" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/cfg" + "github.com/opentelekomcloud/terraform-provider-opentelekomcloud/opentelekomcloud/common/fmterr" +) + +const ( + AssignmentTypeBuiltin = "builtin" + AssignmentTypeCustom = "custom" + + AssignmentStatusDisabled = "Disabled" + AssignmentStatusEnabled = "Enabled" + AssignmentStatusEvaluating = "Evaluating" +) + +func ResourceRmsPolicyAssignmentV1() *schema.Resource { + return &schema.Resource{ + CreateContext: resourcePolicyAssignmentCreate, + ReadContext: resourcePolicyAssignmentRead, + UpdateContext: resourcePolicyAssignmentUpdate, + DeleteContext: resourcePolicyAssignmentDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + }, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "policy_definition_id": { + Type: schema.TypeString, + Optional: true, + }, + "period": { + Type: schema.TypeString, + Optional: true, + }, + "policy_filter": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + }, + "resource_provider": { + Type: schema.TypeString, + Optional: true, + }, + "resource_type": { + Type: schema.TypeString, + Optional: true, + }, + "resource_id": { + Type: schema.TypeString, + Optional: true, + }, + "tag_key": { + Type: schema.TypeString, + Optional: true, + }, + "tag_value": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"policy_filter.0.tag_key"}, + }, + }, + }, + }, + "custom_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "function_urn": { + Type: schema.TypeString, + Required: true, + }, + "auth_type": { + Type: schema.TypeString, + Required: true, + }, + "auth_value": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringIsJSON, + }, + }, + }, + }, + }, + "parameters": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringIsJSON, + }, + }, + "status": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func buildPolicyFilter(filters []interface{}) compliance.PolicyFilterDefinition { + if len(filters) < 1 { + return compliance.PolicyFilterDefinition{} + } + filter := filters[0].(map[string]interface{}) + return compliance.PolicyFilterDefinition{ + RegionID: filter["region"].(string), + ResourceProvider: filter["resource_provider"].(string), + ResourceType: filter["resource_type"].(string), + ResourceID: filter["resource_id"].(string), + TagKey: filter["tag_key"].(string), + TagValue: filter["tag_value"].(string), + } +} + +func buildCustomPolicy(policies []interface{}) (*compliance.CustomPolicy, error) { + if len(policies) < 1 { + return nil, nil + } + policy := policies[0].(map[string]interface{}) + result := compliance.CustomPolicy{ + FunctionUrn: policy["function_urn"].(string), + AuthType: policy["auth_type"].(string), + } + authValues := make(map[string]interface{}) + for k, jsonVal := range policy["auth_value"].(map[string]interface{}) { + var value interface{} + err := json.Unmarshal([]byte(jsonVal.(string)), &value) + if err != nil { + return &result, fmt.Errorf("error analyzing authorization value: %s", err) + } + authValues[k] = value + } + result.AuthValue = authValues + + return &result, nil +} + +func buildRuleParameters(parameters map[string]interface{}) (map[string]compliance.PolicyParameter, error) { + if len(parameters) < 1 { + return nil, nil + } + result := make(map[string]compliance.PolicyParameter) + for k, jsonVal := range parameters { + var value interface{} + err := json.Unmarshal([]byte(jsonVal.(string)), &value) + if err != nil { + return result, fmt.Errorf("error analyzing parameter value: %s", err) + } + result[k] = compliance.PolicyParameter{ + Value: value, + } + } + return result, nil +} + +func buildPolicyAssignmentCreateOpts(d *schema.ResourceData) (compliance.AddRuleOpts, error) { + result := compliance.AddRuleOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + PolicyAssignmentType: AssignmentTypeBuiltin, + PolicyFilter: buildPolicyFilter(d.Get("policy_filter").([]interface{})), + PolicyDefinitionID: d.Get("policy_definition_id").(string), + Period: d.Get("period").(string), + } + customPolicy, err := buildCustomPolicy(d.Get("custom_policy").([]interface{})) + if err != nil { + return result, err + } + result.CustomPolicy = customPolicy + if customPolicy != nil { + result.PolicyAssignmentType = AssignmentTypeCustom + } + + parameters, err := buildRuleParameters(d.Get("parameters").(map[string]interface{})) + if err != nil { + return result, err + } + result.Parameters = parameters + + return result, nil +} + +func updatePolicyAssignmentStatus(client *golangsdk.ServiceClient, domainId, assignmentId, + statusConfig string) (err error) { + switch statusConfig { + case AssignmentStatusDisabled: + err = compliance.DisableRule(client, domainId, assignmentId) + case AssignmentStatusEnabled: + err = compliance.EnableRule(client, domainId, assignmentId) + } + return +} + +func policyAssignmentRefreshFunc(client *golangsdk.ServiceClient, domainId, + assignmentId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := compliance.GetRule(client, domainId, assignmentId) + if err != nil { + return resp, "ERROR", err + } + return resp, resp.State, nil + } +} + +func resourcePolicyAssignmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*cfg.Config) + client, err := common.ClientFromCtx(ctx, rmsClientV1, func() (*golangsdk.ServiceClient, error) { + return config.RmsV1Client(config.GetRegion(d)) + }) + if err != nil { + return fmterr.Errorf(errCreationRMSV1Client, err) + } + + opts, err := buildPolicyAssignmentCreateOpts(d) + if err != nil { + return diag.Errorf("error creating the create option structure of the RMS policy assignment: %s", err) + } + domainId := GetRmsDomainId(client, config) + opts.DomainId = domainId + + resp, err := compliance.AddRule(client, opts) + if err != nil { + return diag.Errorf("error creating policy assignment resource: %s", err) + } + + assignmentId := resp.ID + d.SetId(assignmentId) + + // it will take too long time to become enabled when the resources are very huge. + // so we wait for the enabled status only when user want to disable it during creating. + if statusConfig := d.Get("status").(string); statusConfig == AssignmentStatusDisabled { + log.Printf("[DEBUG] Waiting for the policy assignment (%s) status to become enabled, then disable it", assignmentId) + stateConf := &resource.StateChangeConf{ + Pending: []string{AssignmentStatusDisabled, AssignmentStatusEvaluating}, + Target: []string{AssignmentStatusEnabled}, + Refresh: policyAssignmentRefreshFunc(client, domainId, assignmentId), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + PollInterval: 10 * time.Second, + ContinuousTargetOccurence: 2, + } + _, err = stateConf.WaitForStateContext(ctx) + if err != nil { + return diag.Errorf("error waiting for the policy assignment (%s) status to become enabled: %s", + assignmentId, err) + } + + err = updatePolicyAssignmentStatus(client, domainId, assignmentId, statusConfig) + if err != nil { + return diag.Errorf("error disabling the status of the policy assignment: %s", err) + } + } + + clientCtx := common.CtxWithClient(ctx, client, errCreationRMSV1Client) + return resourcePolicyAssignmentRead(clientCtx, d, meta) +} + +func flattenPolicyFilter(filter compliance.PolicyFilterDefinition) []map[string]interface{} { + if reflect.DeepEqual(filter, compliance.PolicyFilterDefinition{}) { + return nil + } + + return []map[string]interface{}{ + { + "region": filter.RegionID, + "resource_provider": filter.ResourceProvider, + "resource_type": filter.ResourceType, + "resource_id": filter.ResourceID, + "tag_key": filter.TagKey, + "tag_value": filter.TagValue, + }, + } +} + +func flattenCustomPolicy(customPolicy *compliance.CustomPolicy) ([]map[string]interface{}, error) { + if customPolicy == nil { + return nil, nil + } + + authValues := make(map[string]interface{}) + for k, v := range customPolicy.AuthValue { + jsonBytes, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("generate json string failed: %s", err) + } + authValues[k] = string(jsonBytes) + } + return []map[string]interface{}{ + { + "function_urn": customPolicy.FunctionUrn, + "auth_type": customPolicy.AuthType, + "auth_value": authValues, + }, + }, nil +} + +func flattenPolicyParameters(parameters map[string]compliance.PolicyParameter) (map[string]interface{}, + error) { + if len(parameters) < 1 { + return nil, nil + } + + result := make(map[string]interface{}) + for k, v := range parameters { + jsonBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, fmt.Errorf("generate json string failed: %s", err) + } + result[k] = string(jsonBytes) + } + return result, nil +} + +func resourcePolicyAssignmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*cfg.Config) + client, err := common.ClientFromCtx(ctx, rmsClientV1, func() (*golangsdk.ServiceClient, error) { + return config.RmsV1Client(config.GetRegion(d)) + }) + if err != nil { + return fmterr.Errorf(errCreationRMSV1Client, err) + } + + domainId := GetRmsDomainId(client, config) + assignmentId := d.Id() + resp, err := compliance.GetRule(client, domainId, assignmentId) + if err != nil { + return common.CheckDeletedDiag(d, err, "RMS policy assignment") + } + + customPolicy, err := flattenCustomPolicy(resp.CustomPolicy) + if err != nil { + return diag.FromErr(err) + } + parameters, err := flattenPolicyParameters(resp.Parameters) + if err != nil { + return diag.FromErr(err) + } + mErr := multierror.Append(nil, + d.Set("type", resp.PolicyAssignmentType), + d.Set("name", resp.Name), + d.Set("description", resp.Description), + d.Set("policy_definition_id", resp.PolicyDefinitionID), + d.Set("period", resp.Period), + d.Set("policy_filter", flattenPolicyFilter(*resp.PolicyFilter)), + d.Set("custom_policy", customPolicy), + d.Set("parameters", parameters), + d.Set("status", resp.State), + d.Set("created_at", resp.Created), + d.Set("updated_at", resp.Updated), + ) + + if mErr.ErrorOrNil() != nil { + return diag.Errorf("error saving policy assignment resource (%s) fields: %s", assignmentId, mErr) + } + return nil +} + +func buildPolicyAssignmentUpdateOpts(d *schema.ResourceData) (compliance.UpdateRuleOpts, error) { + result := compliance.UpdateRuleOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + PolicyAssignmentType: AssignmentTypeBuiltin, + PolicyFilter: buildPolicyFilter(d.Get("policy_filter").([]interface{})), + PolicyDefinitionID: d.Get("policy_definition_id").(string), + Period: d.Get("period").(string), + } + customPolicy, err := buildCustomPolicy(d.Get("custom_policy").([]interface{})) + if err != nil { + return result, err + } + result.CustomPolicy = customPolicy + if customPolicy != nil { + result.PolicyAssignmentType = AssignmentTypeCustom + } + + parameters, err := buildRuleParameters(d.Get("parameters").(map[string]interface{})) + if err != nil { + return result, err + } + result.Parameters = parameters + + return result, nil +} + +func resourcePolicyAssignmentUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*cfg.Config) + client, err := common.ClientFromCtx(ctx, rmsClientV1, func() (*golangsdk.ServiceClient, error) { + return config.RmsV1Client(config.GetRegion(d)) + }) + if err != nil { + return fmterr.Errorf(errCreationRMSV1Client, err) + } + + assignmentId := d.Id() + domainId := GetRmsDomainId(client, config) + + if d.HasChange("status") { + oldVal, newVal := d.GetChange("status") + err = updatePolicyAssignmentStatus(client, domainId, d.Id(), d.Get("status").(string)) + if err != nil { + return diag.Errorf("error updating the status of the policy assignment (%s): %s", assignmentId, err) + } + + if newVal.(string) == AssignmentStatusEnabled { + log.Printf("[DEBUG] Waiting for the policy assignment (%s) status to become %s.", assignmentId, + strings.ToLower(newVal.(string))) + stateConf := &resource.StateChangeConf{ + Pending: []string{oldVal.(string)}, + Target: []string{AssignmentStatusEvaluating, AssignmentStatusEnabled}, + Refresh: policyAssignmentRefreshFunc(client, domainId, assignmentId), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + PollInterval: 10 * time.Second, + ContinuousTargetOccurence: 2, + } + _, err = stateConf.WaitForStateContext(ctx) + if err != nil { + return diag.Errorf("error waiting for the policy assignment (%s) status to become %s: %s", + assignmentId, strings.ToLower(newVal.(string)), err) + } + } + } + if d.HasChangeExcept("status") { + opts, err := buildPolicyAssignmentUpdateOpts(d) + if err != nil { + return diag.Errorf("error creating the update option structure of the RMS policy assignment: %s", err) + } + + opts.DomainId = domainId + opts.PolicyAssignmentId = assignmentId + + _, err = compliance.UpdateRule(client, opts) + if err != nil { + return diag.Errorf("error updating policy assignment resource (%s): %s", assignmentId, err) + } + currentStatus := d.Get("status").(string) + log.Printf("[DEBUG] Waiting for the policy assignment (%s) status to become %s.", assignmentId, + strings.ToLower(currentStatus)) + stateConf := &resource.StateChangeConf{ + Target: []string{currentStatus}, + Refresh: policyAssignmentRefreshFunc(client, domainId, assignmentId), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + PollInterval: 10 * time.Second, + ContinuousTargetOccurence: 2, + } + _, err = stateConf.WaitForStateContext(ctx) + if err != nil { + return diag.Errorf("error waiting for the policy assignment (%s) status to become %s: %s", + assignmentId, strings.ToLower(currentStatus), err) + } + } + + return resourcePolicyAssignmentRead(ctx, d, meta) +} + +func resourcePolicyAssignmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*cfg.Config) + client, err := common.ClientFromCtx(ctx, rmsClientV1, func() (*golangsdk.ServiceClient, error) { + return config.RmsV1Client(config.GetRegion(d)) + }) + if err != nil { + return fmterr.Errorf(errCreationRMSV1Client, err) + } + var ( + assignmentId = d.Id() + domainId = GetRmsDomainId(client, config) + ) + if d.Get("status").(string) == AssignmentStatusEnabled { + err = compliance.DisableRule(client, domainId, assignmentId) + if err != nil { + return diag.Errorf("failed to disable the policy assignment (%s): %s", assignmentId, err) + } + } + + err = compliance.Delete(client, domainId, assignmentId) + if err != nil { + return diag.Errorf("error deleting the policy assignment (%s): %s", assignmentId, err) + } + return nil +} diff --git a/releasenotes/notes/rms_policies-0f92edd815065b57.yaml b/releasenotes/notes/rms_policies-0f92edd815065b57.yaml new file mode 100644 index 000000000..e1cfe2299 --- /dev/null +++ b/releasenotes/notes/rms_policies-0f92edd815065b57.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + **[RMS]** Add new resource ``resource/opentelekomcloud_rms_policy_assignment_v1`` (`#2701 `_) + - | + **[RMS]** Add new data source ``data_source/opentelekomcloud_rms_policy_definitions_v1`` (`#2701 `_)