diff --git a/CHANGELOG.md b/CHANGELOG.md index b7fe39abc..fbefa639e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # RELEASE NOTES +## 1.3.0 (Feb 25, 2021) APPSEC - Extended list of supported list endpoints from APPSEC API + +#### BREAKING CHANGES: +* PAPI + * `data_akamai_property_rules_template:` snippets files should now be placed under `property-snippets` directory and should have `.json` extension + +#### FEATURES/ENHANCEMENTS: +* APPSEC + * Custom Deny + * SIEM Setting + * Advanced Options Settings + * API Match Target + * API Request Constraint + * Create/Delete/Rename Security Policy + * Host Coverage / Edit Version Notes + * All WAP Features / WAP Hostname Evaluation + * Create Security Configuration + * Rename Security Configuration Version + * Delete Security Configuration Version + * Clone Security Configuration + * Import tool for adding existing resources to Terraform state ([#207](https://github.com/akamai/terraform-provider-akamai/issues/207)) +* DNS + * Create SOA and NS Records on zone read if don't exist. + * Add HTTPS, SVCB record support +* GTM + * Add validation for property type and traffic targets combination + +#### BUG FIXES: +* PAPI + * Fixed issue causing hostnames to be appended instead of being replaced + * Fixed issue causing version and rule comments being dropped ([#55](https://github.com/akamai/terraform-provider-akamai/issues/55)) + * Fixed client side validation to allow certain PAPI errors to passthrough + * Fixed issue causing incorrect property version being stored in state for certain scenarios +* DNS + * Suppress NS Record target diff if old and new equal without trailing 'period' ([#189](https://github.com/akamai/terraform-provider-akamai/issues/189)) + * Fail on attempted Zone deletion. Not supported. + ## 1.2.1 (Feb 4, 2021) #### BUG FIXES: diff --git a/docs/data-sources/appsec_advanced_settings_logging.md b/docs/data-sources/appsec_advanced_settings_logging.md new file mode 100644 index 000000000..c3e3b7505 --- /dev/null +++ b/docs/data-sources/appsec_advanced_settings_logging.md @@ -0,0 +1,74 @@ +--- +layout: "akamai" +page_title: "Akamai: AdvancedSettingsLogging" +subcategory: "Application Security" +description: |- + AdvancedSettingsLogging +--- + +# akamai_appsec_advanced_settings_logging + +Use the `akamai_appsec_advanced_settings_logging` data source to retrieve information about the HTTP header logging controls for a configuration. This operation applies at the configuration level, and therefore applies to all policies within a configuration. You may retrieve these settings for a particular policy by specifying the policy using the security_policy_id parameter. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#gethttpheaderloggingforaconfiguration). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the advanced settings loggings in a given security configuration +// when policy is set - /appsec/v1/configs/{configId}/versions/{versionNum}/security-policies/{policyId}/advanced-settings/logging +// with out policy - /appsec/v1/configs/{configId}/versions/{versionNum}/advanced-settings/logging +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_advanced_settings_logging" "logging" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +output "advanced_settings_logging_output" { + value = data.akamai_appsec_advanced_settings_logging.logging.output_text +} + +output "advanced_settings_logging_json" { + value = data.akamai_appsec_advanced_settings_logging.logging.json +} + +data "akamai_appsec_advanced_settings_logging" "policy_override" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id +} + +output "advanced_settings_policy_logging_output" { + value = data.akamai_appsec_advanced_settings_logging.policy_override.output_text +} + +output "advanced_settings_policy_logging_json" { + value = data.akamai_appsec_advanced_settings_logging.policy_override.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID. + +* `version` - (Required) The version number of the configuration. + +* `security_policy_id` - (Optional) The ID of the security policy to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of information about the logging settings. + +* `output_text` - A tabular display showing the logging settings. + diff --git a/docs/data-sources/appsec_advanced_settings_prefetch.md b/docs/data-sources/appsec_advanced_settings_prefetch.md new file mode 100644 index 000000000..e42db6769 --- /dev/null +++ b/docs/data-sources/appsec_advanced_settings_prefetch.md @@ -0,0 +1,58 @@ +--- +layout: "akamai" +page_title: "Akamai: AdvancedSettingsPrefetch" +subcategory: "Application Security" +description: |- + AdvancedSettingsPrefetch +--- + +# akamai_appsec_advanced_settings_prefetch + +Use the `akamai_appsec_advanced_settings_prefetch` data source to retrieve information the prefetch request settings for a security configuration. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getprefetchrequestsforaconfiguration). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the prefetch request settings for a given security configuration +// with out policy - /appsec/v1/configs/{configId}/versions/{versionNum}/advanced-settings/logging +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_advanced_settings_prefetch" "prefetch" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +//tabular data of all fields - 3 boolean fields and one extensions text +output "advanced_settings_prefetch_output" { + value = data.akamai_appsec_advanced_settings_prefetch.prefetch.output_text +} + +output "advanced_settings_prefetch_json" { + value = data.akamai_appsec_advanced_settings_prefetch.prefetch.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID. + +* `version` - (Required) The version number of the configuration. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of information about the prefetch request settings. + +* `output_text` - A tabular display showing the prefetch request settings. + diff --git a/docs/data-sources/appsec_api_endpoints.md b/docs/data-sources/appsec_api_endpoints.md new file mode 100644 index 000000000..af3d042da --- /dev/null +++ b/docs/data-sources/appsec_api_endpoints.md @@ -0,0 +1,50 @@ +--- +layout: "akamai" +page_title: "Akamai: ApiEndpoints" +subcategory: "Application Security" +description: |- + ApiEndpoints +--- + +# akamai_appsec_api_endpoints + +Use the `akamai_appsec_api_endpoints` data source to retrieve information about the API Endpoints associated with a security policy or configuration version. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getapiendpoints). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_api_endpoints" "api_endpoints" { + config_id = 43253 + version = 7 + api_name = "TestEndpoint" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID. + +* `version` - (Required) The version number of the configuration. + +* `security_policy_id` - (Optional) The ID of the security policy to use. + +* `api_name` - (Optional) The name of a specific endpoint. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `id_list` - A list of IDs of the API endpoints. + +* `json` - A JSON-formatted list of information about the API endpoints. + +* `output_text` - A tabular display showing the ID and name of the API endpoints. + diff --git a/docs/data-sources/appsec_api_request_constraints.md b/docs/data-sources/appsec_api_request_constraints.md new file mode 100644 index 000000000..3fd693f17 --- /dev/null +++ b/docs/data-sources/appsec_api_request_constraints.md @@ -0,0 +1,77 @@ +--- +layout: "akamai" +page_title: "Akamai: ApiRequestConstraints" +subcategory: "Application Security" +description: |- + ApiRequestConstraints +--- + +# akamai_appsec_api_request_constraints + +Use the `akamai_appsec_api_request_constraints` data source to retrieve a list of APIs with their constraints and associated actions, or the constraints and actions for a particular API. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getapirequestconstraints). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the all api request constraints associated with a given security policy +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} +data "akamai_appsec_api_request_constraints" "apis_request_constraints" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id +} + +//endpoint id and action +output "apis_constraints_text" { + value = data.akamai_appsec_api_request_constraints.apis_request_constraints.output_text +} + +output "apis_constraints_json" { + value = data.akamai_appsec_api_request_constraints.apis_request_constraints.json +} + +// USE CASE: user wants to view action on a single api request constraint associated with a given security policy +data "akamai_appsec_api_request_constraints" "api_request_constraints" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + api_id = var.api_id +} + +output "api_constraints_text" { + value = data.akamai_appsec_api_request_constraints.api_request_constraints.output_text +} + +output "api_constraints_json" { + value = data.akamai_appsec_api_request_constraints.api_request_constraints.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `security_policy_id` - (Required) The ID of the security policy to use. + +* `api_id` - (Optional) The ID of a specific API for which to retrieve constraint information. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of information about the APIs and their constraints and actions. + +* `output_text` - A tabular display showing the APIs and their constraints and actions. + diff --git a/docs/data-sources/appsec_attack_group_actions.md b/docs/data-sources/appsec_attack_group_actions.md index 58cc1066a..8d82994ea 100644 --- a/docs/data-sources/appsec_attack_group_actions.md +++ b/docs/data-sources/appsec_attack_group_actions.md @@ -8,7 +8,7 @@ description: |- # akamai_appsec_attack_group_actions -Use the `akamai_appsec_attack_group_actions` data source to retrieve a list of attack groups with their associated actions, or the action for a specific attack group. +Use the `akamai_appsec_attack_group_actions` data source to retrieve a list of attack groups and actions associated with a security policy or a specific attack group and action associated with a security policy. ## Example Usage diff --git a/docs/data-sources/appsec_attack_group_condition_exception.md b/docs/data-sources/appsec_attack_group_condition_exception.md index 90b572b17..7fb870496 100644 --- a/docs/data-sources/appsec_attack_group_condition_exception.md +++ b/docs/data-sources/appsec_attack_group_condition_exception.md @@ -53,6 +53,7 @@ The following arguments are supported: In addition to the arguments above, the following attributes are exported: -* `output_text` - A tabular display showing the ID, name, and action of all custom rules associated with the specified security configuration, version and security policy. +* `output_text` - A tabular display showing the condition and exception information. * `json` - The condition and exception information in JSON format. + diff --git a/docs/data-sources/appsec_bypass_network_lists.md b/docs/data-sources/appsec_bypass_network_lists.md new file mode 100644 index 000000000..a1d13f0d8 --- /dev/null +++ b/docs/data-sources/appsec_bypass_network_lists.md @@ -0,0 +1,65 @@ +--- +layout: "akamai" +page_title: "Akamai: BypassNetworkLists" +subcategory: "Application Security" +description: |- + BypassNetworkLists +--- + +# akamai_appsec_bypass_network_lists + +Use the `akamai_appsec_bypass_network_lists` data source to retrieve information about which network lists are used in the bypass network lists settings. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getbypassnetworklistsforawapconfigversion). + + +## Example Usage + +Basic usage: + +```hcl + +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to see information about bypass network lists used in a Security Configuration version +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_bypass_network_lists" "bypass_network_lists" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +//Tabular display of ID and Name of the network lists +output "bypass_network_lists_output" { + value = data.akamai_appsec_bypass_network_lists.bypass_network_lists.output_text +} + +output "bypass_network_lists_json" { + value = data.akamai_appsec_bypass_network_lists.bypass_network_lists.json +} + +output "bypass_network_lists_id_list" { + value = data.akamai_appsec_bypass_network_lists.bypass_network_lists.bypass_network_list +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `bypass_network_list` - A list of strings containing the network list IDs. + +* `json` - A JSON-formatted list of information about the bypass network lists. + +* `output_text` - A tabular display showing the bypass network list information. + diff --git a/docs/data-sources/appsec_configuration.md b/docs/data-sources/appsec_configuration.md index 343437357..6726eef12 100644 --- a/docs/data-sources/appsec_configuration.md +++ b/docs/data-sources/appsec_configuration.md @@ -55,7 +55,6 @@ The following arguments are supported: * `name` - (Optional) The name of a specific security configuration. If not supplied, information about all security configurations is returned. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: @@ -69,3 +68,4 @@ In addition to the arguments above, the following attributes are exported: * `staging_version` - The version of the specified security configuration currently active in staging. Returned only if `name` was specified. * `production_version` - The version of the specified security configuration currently active in production. Returned only if `name` was specified. + diff --git a/docs/data-sources/appsec_configuration_version.md b/docs/data-sources/appsec_configuration_version.md index 3ae11751c..a45a8b4c2 100644 --- a/docs/data-sources/appsec_configuration_version.md +++ b/docs/data-sources/appsec_configuration_version.md @@ -54,7 +54,6 @@ output "specific_version_production" { } ``` - ## Argument Reference The following arguments are supported: @@ -63,7 +62,6 @@ The following arguments are supported: * `version` - (Optional) The version number of the security configuration to use. If not supplied, information about all versions of the specified security configuration is returned. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/data-sources/appsec_contracts_groups.md b/docs/data-sources/appsec_contracts_groups.md new file mode 100644 index 000000000..006d724d2 --- /dev/null +++ b/docs/data-sources/appsec_contracts_groups.md @@ -0,0 +1,68 @@ +--- +layout: "akamai" +page_title: "Akamai: ContractsGroups" +subcategory: "Application Security" +description: |- + ContractsGroups +--- + +# akamai_appsec_contracts_groups + +Use the `akamai_appsec_contracts_groups` data source to retrieve information about the contracts and groups for your account. Each object contains the contract, groups associated with the contract, and whether Kona Site Defender or Web Application Protector is the product for that contract. You’ll need this information when you create a new security configuration or when you want to get a list of hostnames still available for use in a security policy. The information available via this data source is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getcontractsandgroupswithksdorwaf). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to see contract group details in an account +data "akamai_appsec_contracts_groups" "contracts_groups" { + contractid = var.contractid + groupid = var.groupid +} + +//tabular data of contractid, displayname and group id +output "contracts_groups_list" { + value = data.akamai_appsec_contracts_groups.contracts_groups.output_text +} + +output "contracts_groups_json" { + value = data.akamai_appsec_contracts_groups.contracts_groups.json +} + +//returns any of the contract/group +output "contract_groups_default_contractid" { + value = data.akamai_appsec_contracts_groups.contracts_groups.default_contractid +} + +output "contract_groups_default_groupid" { + value = data.akamai_appsec_contracts_groups.contracts_groups.default_groupid +} +``` + +## Argument Reference + +The following arguments are supported: + +## Attributes Reference + +* `contractid` - (Optional) The ID of a contract for which to retrieve information. + +* `groupid` - (Optional) The ID of a group for which to retrieve information. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the contract and group information. + +* `output_text` - A tabular display showing the contract and group information. + +* `default_contractid` - The default contract ID for the specified contract and group. + +* `default_groupid` - The default group ID for the specified contract and group. + diff --git a/docs/data-sources/appsec_custom_deny.md b/docs/data-sources/appsec_custom_deny.md new file mode 100644 index 000000000..0a5007ab5 --- /dev/null +++ b/docs/data-sources/appsec_custom_deny.md @@ -0,0 +1,75 @@ +--- +layout: "akamai" +page_title: "Akamai: CustomDeny" +subcategory: "Application Security" +description: |- + CustomDeny +--- + +# akamai_appsec_custom_deny + +Use the `akamai_appsec_custom_deny` data source to retrieve information about custom deny actions for a specific security configuration version, or about a particular custom deny action. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getcustomdeny). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the custom deny data with a given security configuration +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_custom_deny" "custom_deny_list" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +//tabular data with id and name +output "custom_deny_list_output" { + value = data.akamai_appsec_custom_deny.custom_deny_list.output_text +} + +output "custom_deny_list_json" { + value = data.akamai_appsec_custom_deny.custom_deny_list.json +} + +// USE CASE: user wants to see a single custom deny associated with a given security configuration version +data "akamai_appsec_custom_deny" "custom_deny" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + custom_deny_id = var.custom_deny_id +} + +output "custom_deny_json" { + value = data.akamai_appsec_custom_deny.custom_deny.json +} + +output "custom_deny_output" { + value = data.akamai_appsec_custom_deny.custom_deny.output_text +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `custom_deny_id` - (Optional) The ID of a specific custom deny action. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the custom deny action information. + +* `output_text` - A tabular display showing the custom deny action information. + + diff --git a/docs/data-sources/appsec_custom_rule_actions.md b/docs/data-sources/appsec_custom_rule_actions.md index 1246e74a8..8bde9a3ca 100644 --- a/docs/data-sources/appsec_custom_rule_actions.md +++ b/docs/data-sources/appsec_custom_rule_actions.md @@ -24,7 +24,7 @@ data "akamai_appsec_configuration" "configuration" { data "akamai_appsec_custom_rule_actions" "custom_rule_actions" { config_id = data.akamai_appsec_configuration.configuration.config_id version = data.akamai_appsec_configuration.configuration.latest_version - policy_id = "crAP_75829" + security_policy_id = "crAP_75829" } output "custom_rule_actions" { value = data.akamai_appsec_custom_rule_actions.custom_rule_actions.output_text diff --git a/docs/data-sources/appsec_custom_rules.md b/docs/data-sources/appsec_custom_rules.md index e7f023874..09e7ed906 100644 --- a/docs/data-sources/appsec_custom_rules.md +++ b/docs/data-sources/appsec_custom_rules.md @@ -16,31 +16,48 @@ Basic usage: ```hcl provider "akamai" { - appsec_section = "default" + edgerc = "~/.edgerc" } +// USE CASE: user wants to see the custom rules associated with a given security configuration data "akamai_appsec_configuration" "configuration" { - name = "Akamai Tools" + name = var.security_configuration } - data "akamai_appsec_custom_rules" "custom_rules" { config_id = data.akamai_appsec_configuration.configuration.config_id } - -output "custom_rules_list" { +output "custom_rules_output_text" { value = data.akamai_appsec_custom_rules.custom_rules.output_text } +output "custom_rules_json" { + value = data.akamai_appsec_custom_rules.custom_rules.json +} +output "custom_rules_config_id" { + value = data.akamai_appsec_custom_rules.custom_rules.config_id +} +// USE CASE: user wants to see a specific custom rule +data "akamai_appsec_custom_rules" "specific_custom_rule" { + config_id = data.akamai_appsec_configuration.configuration.config_id + custom_rule_id = var.custom_rule_id +} +output "specific_custom_rule_json" { + value = data.akamai_appsec_custom_rules.specific_custom_rule.json +} ``` ## Argument Reference -The following argument is supported: +The following arguments are supported: * `config_id` - (Required) The ID of the security configuration to use. +* `custom_rule_id` - (Optional) The ID of a specific custom rule to use. If not supplied, information about all custom rules associated with the given security configuration will be returned. + ## Attributes Reference In addition to the argument above, the following attribute is exported: -* `output_text` - A tabular display showing the ID and name of the custom rules defined for the security configuration. +* `output_text` - A tabular display showing the ID and name of the custom rule(s). + +* `json` - A JSON-formatted display of the custom rule information. diff --git a/docs/data-sources/appsec_eval_hostnames.md b/docs/data-sources/appsec_eval_hostnames.md new file mode 100644 index 000000000..0fb6756b8 --- /dev/null +++ b/docs/data-sources/appsec_eval_hostnames.md @@ -0,0 +1,63 @@ +--- +layout: "akamai" +page_title: "Akamai: EvalHostnames" +subcategory: "Application Security" +description: |- + EvalHostnames +--- + +# akamai_appsec_eval_hostnames + +Use the `akamai_appsec_eval_hostnames` data source to retrieve the evaluation hostnames for a configuration version. Evaluation mode for hostnames is only available for Web Application Protector. Run hostnames in evaluation mode to see how your configuration settings protect traffic for that hostname before adding a hostname directly to a live configuration. An evaluation period lasts four weeks unless you stop the evaluation. Once you begin, the hostnames you evaluate start responding to traffic as if they are your current hostnames. However, instead of taking an action the evaluation hostnames log which action they would have taken if they were your actively-protected hostnames and not a test. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the hosts which are under evaluation in a config version + +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_eval_hostnames" "eval_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +output "eval_hostnames" { + value = data.akamai_appsec_eval_hostnames.eval_hostnames.hostnames +} + +output "eval_hostnames_output" { + value = data.akamai_appsec_eval_hostnames.eval_hostnames.output_text +} + +output "eval_hostnames_json" { + value = data.akamai_appsec_eval_hostnames.eval_hostnames.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `hostnames` - A list of the evaluation hostnames. + +* `json` - A JSON-formatted list of the evaluation hostnames. + +* `output_text` - A tabular display showing the evaluation hostnames. + diff --git a/docs/data-sources/appsec_eval_rule_actions.md b/docs/data-sources/appsec_eval_rule_actions.md index 411a659c0..90d552ffe 100644 --- a/docs/data-sources/appsec_eval_rule_actions.md +++ b/docs/data-sources/appsec_eval_rule_actions.md @@ -71,3 +71,4 @@ In addition to the arguments above, the following attributes are exported: * `json` - A JSON-formatted display of the ID and action for all rules in the security policy. * `action` - The action configured for the given rule if a `rule_id` was specified. + diff --git a/docs/data-sources/appsec_failover_hostnames.md b/docs/data-sources/appsec_failover_hostnames.md new file mode 100644 index 000000000..ce259bdd9 --- /dev/null +++ b/docs/data-sources/appsec_failover_hostnames.md @@ -0,0 +1,59 @@ +--- +layout: "akamai" +page_title: "Akamai: FailoverHostnames" +subcategory: "Application Security" +description: |- + FailoverHostnames +--- + +# akamai_appsec_failover_hostnames + +Use the `akamai_appsec_failover_hostnames` data source to retrieve a list of the failover hostnames in a configuration. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getfailoverhostnames). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the failover hostnames in a given security configuration +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_failover_hostnames" "failover_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id +} + +output "failover_hostnames" { + value = data.akamai_appsec_failover_hostnames.failover_hostnames.hostnames +} + +output "failover_hostnames_output" { + value = data.akamai_appsec_failover_hostnames.failover_hostnames.output_text +} + +output "failover_hostnames_json" { + value = data.akamai_appsec_failover_hostnames.failover_hostnames.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +## Attributes Reference + +In addition to the argument above, the following attributes are exported: + +* `hostnames` - A list of the failover hostnames. + +* `json` - A JSON-formatted list of the failover hostnames. + +* `output_text` - A tabular display showing the failover hostnames. + diff --git a/docs/data-sources/appsec_hostname_coverage.md b/docs/data-sources/appsec_hostname_coverage.md new file mode 100644 index 000000000..8729c8fc3 --- /dev/null +++ b/docs/data-sources/appsec_hostname_coverage.md @@ -0,0 +1,53 @@ +--- +layout: "akamai" +page_title: "Akamai: HostnameCoverage" +subcategory: "Application Security" +description: |- + HostnameCoverage +--- + +# akamai_appsec_hostname_coverage + +Use the `akamai_appsec_hostname_coverage` data source to retrieve a list of hostnames in the account with their current protections, activation statuses, and other summary information. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#8eb23096). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the hostname coverage data +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_hostname_coverage" "hostname_coverage" { +} + +output "hostname_coverage_list_json" { + value = data.akamai_appsec_hostname_coverage.hostname_coverage.json +} + +//tabular data of hostname, status, hasMatchTarget +output "hostname_coverage_list_output" { + value = data.akamai_appsec_hostname_coverage.hostname_coverage.output_text +} +``` + +## Argument Reference + +The following arguments are supported: + +* None + +## Attributes Reference + +The following attributes are exported: + +* `json` - A JSON-formatted list of the hostname coverage information. + +* `output_text` - A tabular display of the hostname coverage information. + diff --git a/docs/data-sources/appsec_hostname_coverage_match_targets.md b/docs/data-sources/appsec_hostname_coverage_match_targets.md new file mode 100644 index 000000000..3de2197b2 --- /dev/null +++ b/docs/data-sources/appsec_hostname_coverage_match_targets.md @@ -0,0 +1,46 @@ +--- +layout: "akamai" +page_title: "Akamai: ApiHostnameCoverageMatchTargets" +subcategory: "Application Security" +description: |- + ApiHostnameCoverageMatchTargets +--- + +# akamai_appsec_hostname_coverage_match_targets + +Use the `akamai_appsec_hostname_coverage_match_targets` data source to retrieve information about the API and website match targets that protect a hostname. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#gethostnamecoveragematchtargets). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_hostname_coverage_match_targets" "match_targets" { + config_id = 43253 + version = 7 + hostname = "example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id`- (Required) The configuration ID. + +* `version` - (Required) The version number of the configuration. + +* `hostname` - (Required) The hostname for which to retrieve information. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the coverage information. + +* `output_text` - A tabular display of the coverage information. + diff --git a/docs/data-sources/appsec_hostname_coverage_overlapping.md b/docs/data-sources/appsec_hostname_coverage_overlapping.md new file mode 100644 index 000000000..8f6b6e9b8 --- /dev/null +++ b/docs/data-sources/appsec_hostname_coverage_overlapping.md @@ -0,0 +1,46 @@ +--- +layout: "akamai" +page_title: "Akamai: ApiHostnameCoverageOverlapping" +subcategory: "Application Security" +description: |- + ApiHostnameCoverageOverlapping +--- + +# akamai_appsec_hostname_coverage_overlapping + +Use the `akamai_appsec_hostname_coverage_overlapping` data source to retrieve information about the configuration versions that contain a hostname also included in the current configuration version. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#gethostnamecoverageoverlapping). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_hostname_coverage_overlapping" "test" { + config_id = 43253 + version = 7 + hostname = "example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id`- (Required) The configuration ID. + +* `version` - (Required) The version number of the configuration. + +* `hostname` - (Optional) The hostname for which to retrieve information. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the overlap information. + +* `output_text` - A tabular display of the overlap information. + diff --git a/docs/data-sources/appsec_ip_geo.md b/docs/data-sources/appsec_ip_geo.md index 7c84c1a12..f4e8a40d3 100644 --- a/docs/data-sources/appsec_ip_geo.md +++ b/docs/data-sources/appsec_ip_geo.md @@ -69,5 +69,5 @@ In addition to the arguments above, the following attributes are exported: * `exception_ip_network_lists` - The network lists to be allowed regardless of `mode`, `geo_network_lists`, and `ip_network_lists` parameters. -* `output_txt` - A tabular display of the IP/Geo firewall settings. +* `output_text` - A tabular display of the IP/Geo firewall settings. diff --git a/docs/data-sources/appsec_penalty_box.md b/docs/data-sources/appsec_penalty_box.md index 0aa5e05e7..fa63ed26a 100644 --- a/docs/data-sources/appsec_penalty_box.md +++ b/docs/data-sources/appsec_penalty_box.md @@ -62,3 +62,4 @@ In addition to the arguments above, the following attributes are exported: * `enabled` - Either `true` or `false`, indicating whether penalty box protection is enabled. * `output_text` - A tabular display of the `action` and `enabled` information. + diff --git a/docs/data-sources/appsec_rate_policy_actions.md b/docs/data-sources/appsec_rate_policy_actions.md index 6dc260779..efedbb35a 100644 --- a/docs/data-sources/appsec_rate_policy_actions.md +++ b/docs/data-sources/appsec_rate_policy_actions.md @@ -52,5 +52,3 @@ In addition to the arguments above, the following attributes are exported: * `output_text` - A tabular display showing the ID IPv4Action and IPv6Action of the indicated security policy. - - diff --git a/docs/data-sources/appsec_reputation_profile_actions.md b/docs/data-sources/appsec_reputation_profile_actions.md index a915cf99d..77fa95753 100644 --- a/docs/data-sources/appsec_reputation_profile_actions.md +++ b/docs/data-sources/appsec_reputation_profile_actions.md @@ -60,7 +60,6 @@ The following arguments are supported: * `reputation_profile_id` - (Optional) The ID of a given reputation profile. If not supplied, information about all reputation profiles is returned. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/data-sources/appsec_reputation_profile_analysis.md b/docs/data-sources/appsec_reputation_profile_analysis.md new file mode 100644 index 000000000..5a78ed199 --- /dev/null +++ b/docs/data-sources/appsec_reputation_profile_analysis.md @@ -0,0 +1,59 @@ +--- +layout: "akamai" +page_title: "Akamai: ReputationProfileAnalysis" +subcategory: "Application Security" +description: |- + Reputation Profile Analysis +--- + +# akamai_appsec_reputation_profile_analysis + +Use the `akamai_appsec_reputation_profile_analysis` data source to retrieve information about the current reputation analysis settings. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getreputationanalysis). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the all reputation analysis associated with a given security policy +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_reputation_profile_analysis" "reputation_analysis" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id +} + +output "reputation_analysis_text" { + value = data.akamai_appsec_reputation_profile_analysis.reputation_analysis.output_text +} + +output "reputation_analysis_json" { + value = data.akamai_appsec_reputation_profile_analysis.reputation_analysis.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `security_policy_id` - (Required) The ID of the security policy to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the reputation analysis settings. + +* `output_text` - A tabular display showing the reputation analysis settings. + diff --git a/docs/data-sources/appsec_reputation_profiles.md b/docs/data-sources/appsec_reputation_profiles.md index b26c8a644..76c12bdef 100644 --- a/docs/data-sources/appsec_reputation_profiles.md +++ b/docs/data-sources/appsec_reputation_profiles.md @@ -58,7 +58,6 @@ The following arguments are supported: * `reputation_profile_id` - (Optional) The ID of a given reputation profile. If not supplied, information about all reputation profiles is returned. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/data-sources/appsec_rule_actions.md b/docs/data-sources/appsec_rule_actions.md index 12c926e09..de8309af8 100644 --- a/docs/data-sources/appsec_rule_actions.md +++ b/docs/data-sources/appsec_rule_actions.md @@ -68,3 +68,4 @@ In addition to the arguments above, the following attributes are exported: * `json` - A JSON-formatted display of the ID and action for all rules in the security policy. * `action` - The action configured for the given rule if a `rule_id` was specified. + diff --git a/docs/data-sources/appsec_rule_upgrade_details.md b/docs/data-sources/appsec_rule_upgrade_details.md index a8bfeaecf..1b80f2031 100644 --- a/docs/data-sources/appsec_rule_upgrade_details.md +++ b/docs/data-sources/appsec_rule_upgrade_details.md @@ -53,3 +53,4 @@ In addition to the arguments above, the following attributes are exported: * `output_text` - A tabular display showing changes (additions and deletions) to the rules for the specified security policy. * `json` - A JSON-formatted list of the changes (additions and deletions) to the rules for the specified security policy. + diff --git a/docs/data-sources/appsec_security_policy.md b/docs/data-sources/appsec_security_policy.md index df407402a..6be5025bf 100644 --- a/docs/data-sources/appsec_security_policy.md +++ b/docs/data-sources/appsec_security_policy.md @@ -66,3 +66,4 @@ In addition to the arguments above, the following attributes are exported: * `output_text` - A tabular display showing the ID and name of all security policies. * `policy_id` - The ID of the security policy. Included only if `name` was specified. + diff --git a/docs/data-sources/appsec_security_policy_protections.md b/docs/data-sources/appsec_security_policy_protections.md index c537bb64d..6e386dde6 100644 --- a/docs/data-sources/appsec_security_policy_protections.md +++ b/docs/data-sources/appsec_security_policy_protections.md @@ -78,12 +78,20 @@ The following arguments are supported: In addition to the arguments above, the following attributes are exported: * `apply_application_layer_controls` - `true` or `false`, indicating whether application layer controls are in effect. + * `apply_network_layer_controls` - `true` or `false`, indicating whether network layer controls are in effect. + * `apply_rate_controls` - `true` or `false`, indicating whether rate controls are in effect. + * `apply_reputation_controls` - `true` or `false`, indicating whether reputation controls are in effect. + * `apply_botman_controls` - `true` or `false`, indicating whether botman controls are in effect. + * `apply_api_constraints` - `true` or `false`, indicating whether API constraints are in effect. + * `apply_slow_post_controls` - `true` or `false`, indicating whether slow post controls are in effect. + * `json` - a JSON-formatted list showing the status of the protection settings + * `output_text` - a tabular display showing the status of the protection settings diff --git a/docs/data-sources/appsec_selectable_hostnames.md b/docs/data-sources/appsec_selectable_hostnames.md index 449b4d3b1..9b104ab3b 100644 --- a/docs/data-sources/appsec_selectable_hostnames.md +++ b/docs/data-sources/appsec_selectable_hostnames.md @@ -8,7 +8,7 @@ description: |- # akamai_appsec_selectable_hostnames -Use the `akamai_appsec_selectable_hostnames` data source to retrieve the list of hostnames that may be protected under a given security configuration version. +Use the `akamai_appsec_selectable_hostnames` data source to retrieve the list of hostnames that may be protected under a given security configuration version. You can specify the list to be retrieved either by supplying the name and version of a security configuration, or by supplying a group ID and contract ID. ## Example Usage @@ -16,13 +16,14 @@ Basic usage: ```hcl provider "akamai" { - appsec_section = "default" + edgerc = "~/.edgerc" } +// USE CASE: user wants to view the list of hosts available to be added to the list of those protected +// under a given security configuration and version data "akamai_appsec_configuration" "configuration" { - name = "Akamai Tools" + name = var.security_configuration } - data "akamai_appsec_selectable_hostnames" "selectable_hostnames" { config_id = data.akamai_appsec_configuration.configuration.config_id version = data.akamai_appsec_configuration.configuration.latest_version @@ -32,24 +33,48 @@ output "selectable_hostnames" { value = data.akamai_appsec_selectable_hostnames.selectable_hostnames.hostnames } +// USE CASE: user wants to view the same list of unprotected hostnames, in JSON form output "selectable_hostnames_json" { value = data.akamai_appsec_selectable_hostnames.selectable_hostnames.hostnames_json } +// USE CASE: user wants to view the same list of unprotected hostnames, in tabular form output "selectable_hostnames_output_text" { value = data.akamai_appsec_selectable_hostnames.selectable_hostnames.output_text } +//USE CASE: user wants to view the list of hosts available to create a new config under a given contractid and groupid +data "akamai_appsec_selectable_hostnames" "selectable_hostnames_for_create_configuration" { + contractid = var.contractid + groupid = var.groupid +} + +output "selectable_hostnames_for_create_configuration" { + value = data.akamai_appsec_selectable_hostnames.selectable_hostnames_for_create_configuration.hostnames +} + +// USE CASE: user wants to view the same list of available hostnames, in JSON form +output "selectable_hostnames_for_create_configuration_json" { + value = data.akamai_appsec_selectable_hostnames.selectable_hostnames_for_create_configuration.hostnames_json +} + +// USE CASE: user wants to view the same list of available hostnames, in tabular form +output "selectable_hostnames_for_create_configuration_output_text" { + value = data.akamai_appsec_selectable_hostnames.selectable_hostnames_for_create_configuration.output_text +} ``` ## Argument Reference The following arguments are supported: -* `config_id` - (Required) The ID of the security configuration to use. +* `config_id` - (Optional) The ID of the security configuration to use. + +* `version` - (Optional) The version number of the security configuration to use. -* `version` - (Required) The version number of the security configuration to use. +* `contractid` - (Optional) The ID of the contract to use. +* `groupid` - (Optional) The ID of the group to use. ## Attributes Reference diff --git a/docs/data-sources/appsec_selected_hostnames.md b/docs/data-sources/appsec_selected_hostnames.md index 5f16eef64..08fe15be0 100644 --- a/docs/data-sources/appsec_selected_hostnames.md +++ b/docs/data-sources/appsec_selected_hostnames.md @@ -49,7 +49,6 @@ The following arguments are supported: * `version` - (Required) The version number of the security configuration to use. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/data-sources/appsec_siem_definitions.md b/docs/data-sources/appsec_siem_definitions.md new file mode 100644 index 000000000..4fb418b24 --- /dev/null +++ b/docs/data-sources/appsec_siem_definitions.md @@ -0,0 +1,60 @@ +--- +layout: "akamai" +page_title: "Akamai: SiemDefinitions" +subcategory: "Application Security" +description: |- + SiemDefinitions +--- + +# akamai_appsec_siem_definitions + +Use the `akamai_appsec_siem_definitions` data source to retrieve information about the available SIEM versions, or about a specific SIEM version. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getsiemversions). + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the siem settings with a given security configuration +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_siem_definitions" "siem_definitions" { +} + +output "siem_definitions_json" { + value = data.akamai_appsec_siem_definitions.siem_definitions.json +} + +output "siem_definitions_output" { + value = data.akamai_appsec_siem_definitions.siem_definitions.output_text +} + +data "akamai_appsec_siem_definitions" "siem_definition" { + siem_definition_name = var.siem_definition_name +} + +output "siem_definition_id" { + value = data.akamai_appsec_siem_definitions.siem_definition.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `siem_definition_name`- (Optional) The name of a specific SIEM definition for which to retrieve information. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the SIEM version information. + +* `output_text` - A tabular display showing the ID and name of each SIEM version. + diff --git a/docs/data-sources/appsec_siem_settings.md b/docs/data-sources/appsec_siem_settings.md new file mode 100644 index 000000000..e7d7f96a3 --- /dev/null +++ b/docs/data-sources/appsec_siem_settings.md @@ -0,0 +1,57 @@ +--- +layout: "akamai" +page_title: "Akamai: SiemSettings" +subcategory: "Application Security" +description: |- + SiemSettijgs +--- + +# akamai_appsec_siem_settings + +Use the `akamai_appsec_siem_settings` data source to retrieve the SIEM settings for a specific configuration. The information available is described [here](https://developer.akamai.com/api/cloud_security/application_security/v1.html#getsiemsettings). + +## Example Usage + +Basic usage: + +```hcl +// OPEN API --> https://developer.akamai.com/api/cloud_security/application_security/v1.html#getsiemsettings +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to view the siem settings with a given security configuration +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_siem_settings" "siem_settings" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +output "siem_settings_json" { + value = data.akamai_appsec_siem_settings.siem_settings.json +} + +output "siem_settings_output" { + value = data.akamai_appsec_siem_settings.siem_settings.output_text +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list of the SIEM setting information. + +* `output_text` - A tabular display showing the SIEM setting information. + diff --git a/docs/data-sources/appsec_slow_post.md b/docs/data-sources/appsec_slow_post.md index 23db13390..ba0daad44 100644 --- a/docs/data-sources/appsec_slow_post.md +++ b/docs/data-sources/appsec_slow_post.md @@ -50,8 +50,12 @@ The following arguments are supported: In addition to the arguments above, the following attributes are exported: * `output_text` - A tabular display including the following columns: + * `ACTION` - The action that the rule should trigger (either `alert` or `abort`) + * `SLOW_RATE_THRESHOLD RATE` - The average rate in bytes per second over the period specified by `period` before the specified `action` is triggered. + * `SLOW_RATE_THRESHOLD PERIOD` - The length in seconds of the period during which the server should accept a request before determining whether a POST request is too slow. + * `DURATION_THRESHOLD TIMEOUT` - The time in seconds before the first eight kilobytes of the POST body must be received to avoid triggering the specified `action`. diff --git a/docs/data-sources/appsec_version_notes.md b/docs/data-sources/appsec_version_notes.md new file mode 100644 index 000000000..95ffd89f3 --- /dev/null +++ b/docs/data-sources/appsec_version_notes.md @@ -0,0 +1,56 @@ +--- +layout: "akamai" +page_title: "Akamai: VersionNotes" +subcategory: "Application Security" +description: |- + VersionNotes +--- + +# akamai_appsec_version_notes + +Use the `akamai_appsec_version_notes` data source to retrieve the most recent version notes for a configuration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +// USE CASE: user wants to see version notes of the latest version +data "akamai_appsec_version_notes" "version_notes" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +output "version_notes_text" { + value = data.akamai_appsec_version_notes.version_notes.output_text +} + +output "version_notes_json" { + value = data.akamai_appsec_version_notes.version_notes.json +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `json` - A JSON-formatted list showing the version notes. + +* `output_text` - A tabular display showing the version notes. + diff --git a/docs/data-sources/appsec_waf_mode.md b/docs/data-sources/appsec_waf_mode.md index 5e6adee2d..0dbfd1911 100644 --- a/docs/data-sources/appsec_waf_mode.md +++ b/docs/data-sources/appsec_waf_mode.md @@ -63,7 +63,6 @@ The following arguments are supported: * `security_policy_id` - (Required) The ID of the security policy to use. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/data-sources/appsec_waf_protection.md b/docs/data-sources/appsec_waf_protection.md deleted file mode 100644 index 8b32ce3ec..000000000 --- a/docs/data-sources/appsec_waf_protection.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -layout: "akamai" -page_title: "Akamai: WAF Protection" -subcategory: "Application Security" -description: |- - WAF Protection ---- - -# akamai_appsec_waf_protection - -Use the `akamai_appsec_waf_protection` data source to retrieve the current protection settings for a given security configuration version and policy - - -## Example Usage - -Basic usage: - -```hcl -provider "akamai" { - appsec_section = "default" -} -data "akamai_appsec_configuration" "configuration" { - name = var.security_configuration -} -data "akamai_appsec_waf_protection" "waf_protection" { - config_id = data.akamai_appsec_configuration.configuration.config_id - version = data.akamai_appsec_configuration.configuration.latest_version - policy_id = var.policy_id -} -output "output_text" { - value = data.akamai_appsec_waf_protection.waf_protection.output_text -} -``` - -## Argument Reference - -The following arguments are supported: - -* `config_id` - (Required) The ID of the security configuration to use. - -* `version` - (Required) The version number of the security configuration to use. - -* `policy_id` - (Required) The ID of the security policy to use - -## Attributes Reference - -In addition to the arguments above, the following attributes are exported: - -* `output_text` - A tabular display showing the enabled status (true or false) of the following protection features: - * applyApiConstraints - * applyApplicationLayerControls - * applyBotmanControls - * applyNetworkLayerControls - * applyRateControls - * applyReputationControls - * applySlowPostControls - diff --git a/docs/data-sources/appsec_waf_protections.md b/docs/data-sources/appsec_waf_protections.md deleted file mode 100644 index 1a0f57897..000000000 --- a/docs/data-sources/appsec_waf_protections.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -layout: "akamai" -page_title: "Akamai: Policy Protections" -subcategory: "Application Security" -description: |- - Policy Protections ---- - -# akamai_appsec_waf_protections - -Use the `akamai_appsec_waf_protections` data source to retrieve the protections in place for a given security configuration version and security policy. - -## Example Usage - -Basic usage: - -```hcl -provider "akamai" { - appsec_section = "default" -} - -// USE CASE: user wants to view all security policy protections -data "akamai_appsec_configuration" "configuration" { - name = var.security_configuration -} -data "akamai_appsec_security_policy_protections" "protections" { - config_id = data.akamai_appsec_configuration.configuration.config_id - version = data.akamai_appsec_configuration.configuration.latest_version - security_policy_id = var.security_policy_id -} -output "protections_json" { - value = data.akamai_appsec_security_policy_protections.protections.json -} -output "protections_applyApiConstraints" { - value = data.akamai_appsec_security_policy_protections.protections.apply_api_constraints -} -output "protections_applyApplicationLayerControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_application_layer_controls -} -output "protections_applyBotmanControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_botman_controls -} -output "protections_applyNetworkLayerControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_network_layer_controls -} -output "protections_applyRateControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_rate_controls -} -output "protections_applyReputationControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_reputation_controls -} -output "protections_applySlowPostControls" { - value = data.akamai_appsec_security_policy_protections.protections.apply_slow_post_controls -} -``` - -## Argument Reference - -The following arguments are supported: - -* `config_id` - (Required) The ID of the security configuration to use. - -* `version` - (Required) The version number of the security configuration to use. - -* `security_policy_id` - (Required) The ID of the security policy to use. - -## Attributes Reference - -In addition to the arguments above, the following attributes are exported: - -* `json` - a JSON-formatted list of the protections - -* `apply_api_constraints` - true if api constraints are applied, otherwise false - -* `apply_application_layer_controls` - true if application layer controls are applied, otherwise false - -* `apply_botman_controls` - true if botman controls are applied, otherwise false - -* `apply_network_layer_controls` - true if network layer controls are applied, otherwise false - -* `apply_rate_controls` - true if rate controls are applied, otherwise false - -* `apply_reputation_controls` - true if reputation controls are applied, otherwise false - -* `apply_slow_post_controls` - true if slow post controls are applied, otherwise false diff --git a/docs/data-sources/authorities_set.md b/docs/data-sources/authorities_set.md index 3412ea7bd..9a920d9ba 100644 --- a/docs/data-sources/authorities_set.md +++ b/docs/data-sources/authorities_set.md @@ -8,26 +8,26 @@ description: |- # akamai_authorities_set -Use `akamai_authorities_set` datasource to retrieve a contracts authorities set for use when creating new zones. +Use the `akamai_authorities_set` data source to retrieve a contract's authorities set. You use the authorities set when creating new zones. -## Example Usage +## Example usage Basic usage: -```hcl +``` data "akamai_authorities_set" "example" { contract = "ctr_1-AB123" } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +This data source supports this argument: * `contract` - (Required) The contract ID. -## Attributes Reference +## Attributes reference -The following attributes are returned: +This data source supports this attribute: -* `authorities` - A list of authorities +* `authorities` - A list of authorities. diff --git a/docs/data-sources/gtm_default_datacenter.md b/docs/data-sources/gtm_default_datacenter.md index 87628f81d..33fd0469a 100644 --- a/docs/data-sources/gtm_default_datacenter.md +++ b/docs/data-sources/gtm_default_datacenter.md @@ -3,18 +3,18 @@ layout: "akamai" page_title: "Akamai: gtm_default_datacenter" subcategory: "Global Traffic Management" description: |- - Default Datacenter + Default data center --- # akamai_gtm_default_datacenter -Use `akamai_gtm_default_datacenter` data source to retrieve default datacenter id and nickname. +Use the `akamai_gtm_default_datacenter` data source to retrieve the default data center, ID, and nickname. -## Example Usage +## Example usage Basic usage: -```hcl +``` data "akamai_gtm_default_datacenter" "example_ddc" { name = "example_domain.akadns.net" datacenter = 5400 @@ -29,17 +29,17 @@ resource "akamai_gtm_cidrmap" "example_cidrmap" { } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +This data source supports these arguments: * `domain` - (Required) -* `datacenter` - (Optional. Default 5400) +* `datacenter` - (Optional) The default is `5400`. -## Attributes Reference +## Attributes reference -The following attributes are returned: +This data source supports these attributes: -* `id` - The data resource ID. Format: `:default_datacenter:` -* `datacenter_id` - The default datacenter ID -* `nickname` - The default datacenter nickname +* `id` - The data resource ID. Enter in this format: `:default_datacenter:`. +* `datacenter_id` - The default data center ID. +* `nickname` - The default data center nickname. diff --git a/docs/data-sources/property_rules_template.md b/docs/data-sources/property_rules_template.md index decb83126..3f3cd6fca 100644 --- a/docs/data-sources/property_rules_template.md +++ b/docs/data-sources/property_rules_template.md @@ -24,9 +24,9 @@ You can pass user-defined variables by supplying either: You can split each template out into a series of smaller template files. To add them to this data source, you need to include them in the currently loaded file, which corresponds to the value in the `template_file` argument. For example, to -include `example-file.json` from the `template` directory, use this syntax -including the quotes: `"#include:example-file.json"`. All files are resolved in -relation to the directory that contains the starting template file. +include `example-file.json` from the `property-snippets` directory, use this syntax +including the quotes: `"#include:example-file.json"`. Make sure the `property-snippets` folder contains only `.json` files. +All files are resolved in relation to the directory that contains the starting template file. ## Inserting variables in a template You can also add variables to a template by using a string like `“${env.}"`. You'll need the quotes here too. @@ -56,7 +56,7 @@ In this second example, the variables defined refer to files shared with a [Prop ```hcl data "akamai_property_rules_template" "akarules" { - template_file = abspath("${path.root}/templates/main.json") + template_file = abspath("${path.root}/property-snippets/main.json") var_definition_file = abspath("${path.root}/environments/variableDefinitions.json") var_values_file = abspath("${path.root}/environments/dev.example.com/variables.json") } @@ -66,7 +66,7 @@ data "akamai_property_rules_template" "akarules" { Here's an example of what a JSON-based template file with its nested templates might look like: -templates/main.json: +property-snippets/main.json: ```json { "rules": { @@ -94,7 +94,7 @@ You can then define a Terraform configuration file like this, which pulls in the ```hcl data "akamai_property_rules_template" "example" { - template_file = abspath("${path.root}/templates/main.json") + template_file = abspath("${path.root}/property-snippets/main.json") variables { name = "secure" value = "false" diff --git a/docs/guides/akamai_provider_auth.md b/docs/guides/akamai_provider_auth.md index 178f97582..598743e0e 100644 --- a/docs/guides/akamai_provider_auth.md +++ b/docs/guides/akamai_provider_auth.md @@ -47,12 +47,14 @@ supporting API service names: | **Module** | **API service name** | |-------------|----------------------| | Property Manager (Provisioning and Common modules) | Property Manager (PAPI) | -| Edge DNS (DNS) | DNS-Zone Record Management | -| Global Traffic Management | Traffic Management Configurations | +| Edge DNS (DNS) | DNS Zone Management | +| Global Traffic Management | Global Traffic Management | | Application Security | Application Security | Once you create the supporting API clients you can update your local -`.edgerc file`. +`.edgerc` file. + +**Note:** If you're using the Edge DNS or GTM module, you may also need the Property Manager API service. Whether you need this additional service depends on the contract and group you're using. ## Add your local .edgerc file to your Akamai Provider config @@ -61,12 +63,12 @@ To reference a local `.edgerc` file, you add this line to the top of the Akamai Provider configuration file (`akamai.tf`): ``` -edgerc = \"\~/.edgerc\" +edgerc = "~/.edgerc" ``` -The `\~/.edgerc` is the location of your file on your local machine. In -your Terraform files you can reference individual sections inside the -.edgerc file: +`~/.edgerc` is the location of your credentials file on your local machine. In +your Terraform files, you can reference individual sections inside the +`.edgerc` file: ### Example usage @@ -137,7 +139,7 @@ resource "akamai_dns_record" "example_record" { Arguments supported in the `provider` block: -* edgerc - (Optional) The location of the `.edgerc` file containing credentials. The default is `\$HOME/.edgerc`. +* edgerc - (Optional) The location of the `.edgerc` file containing credentials. The default is `$HOME/.edgerc`. * config_section - (Optional) The credential section to use within the `.edgerc` file for all EdgeGrid calls. If you don't use `config_section`, the Akamai Provider uses the credentials in the `default` section of the `.edgerc` file. #### Deprecated arguments @@ -167,7 +169,7 @@ provider "akamai" { } ``` -You don't need the `edgerc` or `config_section` attributes that you'd use if you were adding your local `.edgerc` file to your Akamai Provider config. +You don't need the `edgerc` or `config_section` attributes that you'd use if you were adding your local `.edgerc` file to your Akamai Provider configuration. ### Argument reference @@ -191,7 +193,7 @@ You can also use environment variables to set credential values. Environment variables take precedence over the settings in the `.edgerc` file. -Your environment variables should be in this format: `AKAMAI{_SECTION_NAME}_\*` +Your environment variables should be in this format: `AKAMAI{_SECTION_NAME}_*` For example, if you're setting up the Provisioning module, you'll need an API client for Property Manager. In your `akamai.tf` file, you'll need to add a `config_section` block with these environment variables: @@ -232,7 +234,7 @@ terraform apply ``` ### Variable reference -When using variables, you'll need to set them up based on the sections of your `.edgerc` file they represent. Your environment variables should be in this format: `AKAMAI{_SECTION_NAME}_\*` +When using variables, you'll need to set them up based on the sections of your `.edgerc` file they represent. Your environment variables should be in this format: `AKAMAI{_SECTION_NAME}_*` These are the variables for the `default` section of your `.edgerc` and what they represent: diff --git a/docs/guides/faq.md b/docs/guides/faq.md deleted file mode 100644 index 2de43b006..000000000 --- a/docs/guides/faq.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -layout: "akamai" -page_title: "Akamai: FAQ (Frequently Asked Questions)" -description: |- - Frequently Asked Questions ---- - -# Frequently Asked Questions - -## Primary Zone Partially Created - -In the rare instance, a primary zone may be only partially created on the Akamai backend; for example in the case of a network error. In this situation, the zone may have been created but not the SOA and NS records. Henceforth, any attempt to manage or administer recordsets in the zone will fail. The SOA and NS records must be manually created in order to continue to manage the configuration. - -The records can be created either thru the [Akamai Control Center](https://control.akamai.com) or via the [CLI-DNS](https://github.com/akamai/cli-dns) package for the [Akamai CLI](https://developer.akamai.com/cli). - -## Migrating an Edge DNS Zone and Records to Terraform - -Migrating an existing Edge DNS Zone can be done in many ways. Two such methods include: using a command line utility or using a step by step construction. - -### Via Command Line Utility - -A package, [CLI-Terraform](https://github.com/akamai/cli-terraform), for the [Akamai CLI](https://developer.akamai.com/cli) provides a time saving means to collect information about, generate a configuration for, and import an existing Edge DNS Zone and its contained recordsets. With the package, you can: - -1. Generate a JSON formatted list of the zone and recordsets -2. Generate a Terraform configuration for the zone and select recordsets -3. Generate a command line script to import all defined resources - -#### Notes -1. Terraform limits the characters that can be part of it's resource names. During construction of the resource configurations invalid characters are replaced with underscore , '_' -2. Terrform does not have any state during import of resources. Discrepencies may be identified in certain field lists during the first plan and/or apply following import as Terraform reconciles configurations and state. These discrepencies will clear following the first apply. -3. The first time plan or apply is run, an update will be shown for the provider defined zone fields: contract and group. - -It is recommended that the existing zone configuration and master file (using the API or Control Center) be downloaded before hand as a backup and reference. Additionally, a terraform plan should be executed after importing to validate the generated tfstate. - -### Via Step By Step Construction - -1. Download your existing zone master file configuration (using the API) as a backup and reference. -2. Using the zone master file as a reference, create a Terraform configuration representing the existing zone and all contained recordsets. Note: In creating each resource block, make note of `required`, `optional` and `computed` fields. -3. Use the Terraform Import command to import the existing zone and contained recordsets; singularly and in serial order. -4. (Optional, Recommended) Review and compare the zone master file content and created `terraform.tfstate` to confirm the zone and all recordsets are represented correctly -5. Execute a `Terraform Plan` on the configuration. The plan should be empty. If not, correct accordingly and repeat until plan is empty and configuration is in sync with the Edge DNS Backend. - -Since Terraform assumes it is the de facto state for any resource it leverages, we strongly recommend staging the zone and recordset imports in a test environment to familiarize yourself with the provider operation and mitigate any risks to the existing Edge DNS zone configuration. - -## Migrating a GTM domain (and contained objects) to Terraform - -Migrating an existing GTM domain can be done in many ways. Two such methods include: - -### Via Command Line Utility - -A package, [CLI-Terraform](https://github.com/akamai/cli-terraform), for the [Akamai CLI](https://developer.akamai.com/cli) provides a time saving means to collect information about, generate a configuration for, and import an existing GTM domain and its contained objects and attributes. With the package, you can: - -1. Generate a JSON formatted list of all domain objects. -2. Generate a Terraform configuration for the domain and contained objects. -3. Generate a command line script to import all defined resources. - -#### Notes -1. Terraform limits the characters that can be part of it's resource names. During construction of the resource configurations invalid characters are replaced with underscore , '_' -2. Terraform does not have any state during import of resources. Discrepancies may be identified in certain field lists during the first plan and/or apply following import as Terraform reconciles configurations and state. These discrepancies will clear following the first apply. -3. The first time plan or apply is run, an update will be shown for the provider defined domain fields: `contract`, `group`, and `wait_on_complete`. - -It is recommended that the existing domain configuration (using the API or Control Center) be downloaded before hand as a backup and reference. Additionally, a terraform plan should be executed after importing to validate the generated tfstate. - -### Via Step By Step Construction - -1. Download your existing domain configuration (using the API or Control Center) as a backup and reference. -2. Using the domain download as a reference, create a Terraform configuration representing the existing domain and all contained GTM objects. Note: In creating each resource block, make note of `required`, `optional`, and `computed` fields. -3. Run `terraform import`. This command imports the existing domain and contained objects one at a time based on the order in the configuration. -4. (Optional, Recommended) Review domain download content and created terraform.tfstate to confirm the domain and all objects are represented correctly -5. Run `terraform plan` on the configuration. The plan should be empty. If not, correct accordingly and repeat until plan is empty and configuration is in sync with the GTM Backend. - -Since Terraform assumes it is the de facto state for any resource it leverages, we strongly recommend staging the domain and objects imports in a test environment to familiarize yourself with the provider operation and mitigate any risks to the existing GTM domain configuration. - -## GTM Terraform Resource Field Representation During Plan and/or Apply - -When using `terraform plan` or `terraform apply`, Terraform presents both fields defined in the configuration and all defined resource fields. Fields are either required, optional or computed as specified in each resource description. Default values for fields will display if not explicitly configured. In many cases, the default will be zero, empty string, or empty list depending on the type. These default or empty values are informational and not included in resource updates. diff --git a/docs/guides/get_started_appsec.md b/docs/guides/get_started_appsec.md index 9836583ef..05a4631d4 100644 --- a/docs/guides/get_started_appsec.md +++ b/docs/guides/get_started_appsec.md @@ -2,41 +2,41 @@ layout: "akamai" page_title: "Akamai: Get Started with Application Security" description: |- - Get Started with Akamai Application Security using Terraform + Application Security in Akamai provider for Terraform --- -# Get Started with Application Security +# Application Security in Akamai provider for Terraform -The Akamai Provider for Terraform provides you the ability to automate the creation, deployment, and management of security configurations, custom rules, match targets and other application security resources. +Application Security (appsec) in the Akamai Terraform provider (provider) enables application +security configurations including the following: +* custom rules. +* match targets. +* other application security resources that operate within the Cloud. -To get more information about Application Security, see the [API documentation](https://developer.akamai.com/api/cloud_security/application_security/v1.html) - -## Configure the Terraform Provider - -Set up your .edgerc credential files as described in [Get Started with Akamai APIs](https://developer.akamai.com/api/getting-started), and include read-write permissions for the Application Security API. - -1. Create a new folder called `terraform` -1. Inside the new folder, create a new file called `akamai.tf`. -1. Add the provider configuration to your `akamai.tf` file: - -```hcl -provider "akamai" { - edgerc = "~/.edgerc" - config_section = "appsec" -} -``` +This Guide is for developers who: +* are interested in implementing or updating an integration of Akamai functionality with Terraform. +* already have some familiarity with Akamai. +* understand how to create and edit the 'akamai.tf' file [see](get_started_akamai.md). + +For details about Akamai's application security, see the [API documentation](https://developer.akamai.com/api/cloud_security/application_security/v1.html) ## Prerequisites -To manage Application Security resources, you need to obtain at a minimum the following information: +To manage Application Security resources, you need to obtain information regarding your +existing security implementation, including the following information: * **Configuration ID**: The ID of the specific security configuration under which the resources are defined. -For certain resources, you will also need other information, such as the version number of the security configuration. The process of obtaining this information is described below. +In many cases, you need additional information, which often includes the +version number of the security configuration (see below). -## Retrieving Security Configuration Information +### Retrieve existing security configuration information -You can obtain the name and ID of the existing security configurations using the [`akamai_appsec_configuration`](../data-sources/appsec_configuration.md) data source. This data source can be used with no additional parameters to output information about all security configurations associated with your account. Add the following to your `akamai.tf` file: +You can obtain the name and ID of the existing security configurations by using the +[`akamai_appsec_configuration`](../data-sources/appsec_configuration.md) data source. +Using it without parameters outputs information about all security configurations associated with your account. + +Add the following to your `akamai.tf` file: ```hcl data "akamai_appsec_configuration" "configurations" { @@ -47,13 +47,30 @@ output "configuration_list" { } ``` -Once you have saved the file, switch to the terminal and initialize Terraform using the command: +Save the resulting text file, and then use terminal to initialize Terraform with the command: ```bash $ terraform init ``` -This command will install the latest version of the Akamai provider, as well as any other providers necessary. To update the Akamai provider version after a new release, simply run `terraform init` again. +This installs the latest version of the Akamai provider, along with any other providers necessary. + +When you need to obtain an update of Akamai provider, run `terraform init` again. + +## Configure the Provider + +Set up your .edgerc credential files as described in [Get Started with Akamai APIs](https://developer.akamai.com/api/getting-started), and include read-write permissions for the Application Security API. + +1. Create a new folder called `terraform` +1. Inside the new folder, create a new file called `akamai.tf`. +1. Add the provider configuration to your `akamai.tf` file: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" + config_section = "appsec" +} +``` ## Test Your Configuration @@ -63,19 +80,26 @@ To test your configuration, use `terraform plan`: $ terraform plan ``` -This command will make Terraform create a plan for the work it will do based on the configuration file. This will not actually make any changes and is safe to run as many times as you like. +This command causes Terraform to create a plan for the work it will do, based on the configuration file. This does *not* actually make any changes and is safe to run as many times as you like. -## Apply Changes +## Apply changes -To actually display the configuration information, or to create or modify resources as described further in this guide, we need to instruct Terraform to `apply` the changes outlined in the plan. To do this, in the terminal, run the command: +To display existing configuration information, or to create or modify resources as described in this guide, tell Terraform to `apply` the changes outlined in the plan by running the command: ```bash $ terraform apply ``` -Once this command has been executed, Terraform will display to the terminal window a formatted list of all existing security configurations under your account, including for each its name and ID (`config_id`), the number of its most recently created version, and the number of the version currently active in staging and production, if applicable. +Terraform responds with a formatted list of all existing security configurations in your account, along with names and IDs (`config_id`), the most recently created version, and the version currently active in staging and production, if applicable. + +When you have identified the desired security configuration by name, you can load that specific configuration into Terraform's state. -When you have identified the desired security configuration by name, you can load that specific configuration into Terraform's state. To do this, edit your `akamai.tf` file to add the `name` parameter to the `akamai_appsec_configuration` data block using the desired configuration name as its value, and change the `output` block so that it gives just the `config_id` attribute of the configuration. After these changes, the portion of your file below the initial `provider` block will look like this: +To load a specific configuration: +1. Identify the desired security configuration by name, +1. Edit your `akamai.tf` file to add the desired `name` parameter to the `akamai_appsec_configuration` data block. +1. Change the `output` block so that it gives just the `config_id` attribute of the configuration. + +After these changes, the section of your file below the initial `provider` block looks like the following example: ```hcl data "akamai_appsec_configuration" "configuration" { @@ -87,20 +111,22 @@ output "ID" { } ``` -If you run `terraform apply` on this file, you should see the `config_id` value of the specific configuration displayed on your terminal. +After running `terraform apply` on this file, the terminal displays `config_id` with the configuration value. + +## Specify configuration to display -## Displaying Information About a Specific Configuration +The provider's [`akamai_appsec_export_configuration`](../data-sources/appsec_export_configuration.md) data source can display complete information about any configuration that you specify, including attributes like custom rules, and selected hostnames. -The provider's [`akamai_appsec_export_configuration`](../data-sources/appsec_export_configuration.md) data source can diplay complete information about a specific configuration, including attributes such as custom rules, selected hostnames, etc. To show these two types of data for the most recent version of your selected configuration, add the following blocks to your `akamai.tf` file: +To show custom rule and selected hostname data for your most recent configuration, add the following blocks to your `akamai.tf` file: ```hcl data "akamai_appsec_export_configuration" "export" { config_id = data.akamai_appsec_configuration.configuration.config_id version = data.akamai_appsec_configuration.configuration.latest_version search = [ - "customRules", - "selectedHosts" - ] + "customRules", + "selectedHosts" + ] } output "exported_configuration_text" { @@ -108,7 +134,10 @@ output "exported_configuration_text" { } ``` -Note that you can specify a version of the configuration other than the most recent version. See the [`akamai_configuration_version`](../data-sources/appsec_configuration_version.md) data source to list the available versions. Also, you can specify other kinds of data to be exported besides `customRules` and `selectedHosts`, using any of these search fields: +NOTE: You can specify any available version of the configuration. +See the [`akamai_configuration_version`](../data-sources/appsec_configuration_version.md) +data source to list the available versions. You can also specify other kinds of data for export +using any of the following search fields: * customRules * matchTargets @@ -121,9 +150,12 @@ Note that you can specify a version of the configuration other than the most rec Save the file and run `terraform apply` to see a formatted display of the selected data. -## Adding a Hostname to the `selectedHosts` List +## Add a hostname to the `selectedHosts` list -You can modify the list of hosts protected by a given security configuration using the [`akamai_appsec_selected_hostnames`](../data-sources/appsec_selected_hostnames.md) resource. Add the following resource block to your `akamai.tf` file, replacing `example.com` with a hostname from the list reported in the `data_akamai_appsec_export_configuration` data source example above: +You can modify the list of hosts protected by a specific security configuration using +the [`akamai_appsec_selected_hostnames`](../data-sources/appsec_selected_hostnames.md) resource. +Add the following resource block to your `akamai.tf` file, replacing `example.com` with a hostname +from the list reported in the `data_akamai_appsec_export_configuration` data source example above: ```hcl resource "akamai_appsec_selected_hostnames" "selected_hostnames_append" { @@ -138,13 +170,17 @@ output "selected_hostnames_appended" { } ``` -Once you save the file and run `terraform apply`, Terraform will update the list of selected hosts and output the new list as the value `selected_hostnames_appended`. +When you save the file and run `terraform apply`, Terraform updates the list of selected hosts and outputs the new list as values for `selected_hostnames_appended`. + +NOTE: You cannot modify a security configuration version that is currently active in staging or production, so the resource block above must specify an inactive version. + +After completing your changes to a security configuration version, you can activate it in staging. -Note that you cannot modify a security configuration version that is currently active in staging or production, so the resource block above must specify an inactive version. Once you have completed any changes you want to make to a security configuration version, you can activate it in staging. +## Activate a configuration version -## Activating a Security Configuration Version +To activate a specific configuration version, use the [`akamai_appsec_activations`](../resources/appsec_activations.md) resource. -You can activate a specific version of a security configuration using the [`akamai_appsec_activations`](../resources/appsec_activations.md) resource. Add the following resource block to your `akamai.tf` file, replacing the `version` value with the number of a currently inactive version, such as the one you modified using the `akamai_appsec_selected_hostnames` resource above. +Add the following resource block to your `akamai.tf` file, replacing the `version` value with the number of a currently inactive version, perhaps the one you modified using the `akamai_appsec_selected_hostnames` resource above. ```hcl resource "akamai_appsec_activations" "activation" { @@ -156,56 +192,98 @@ resource "akamai_appsec_activations" "activation" { } ``` -Once you save the file and run `terraform apply`, Terraform will activate the security configuration version in staging. When the activation is complete, an email will be sent to any addresses specified in the `notification_emails` list. +After you save the file and run `terraform apply`, Terraform activates the configuration version in staging. Upon completion of the activation, emails are sent to the addresses specified in the `notification_emails` list. + +## Importing a Resource + +Terraform allows you to add a resource to its state even if this resource was created outside of Terraform, for example by using the Control Center application. This allows you to keep Terraform's state in sync with the state of your actual infrastructure. To do this, use the `terraform import` command with a configuration file that includes a description of the existing resource. The `import` command requires that you specify both the `address` and `ID` of the resource. The `address` indicates the destination to which the resource should be imported; typically this is the resource type and local name of the resource as described in the local configuration file. For example, suppose a new security policy has been created outside of Terraform. You can use the information available in the Control Center to create a matching description of this policy in your local configuration file. Here is an example using fictitious values for the resource's parameters: + +```hcl +data "akamai_appsec_configuration" "configuration" { + name = "Configuration XYZ" +} +resource "akamai_appsec_security_policy" "security_policy_create" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + default_settings = true + security_policy_name = "Security Policy XYZ" + security_policy_prefix = "XYZ" +} +``` + +The `address` of this resource is found by combining the resource type and its local name within the configuration file: "akamai_appsec_security_policy.security_policy_create". +The `ID` indicates the unique identifier for this resource within Terraform's state. Its format varies depending on the resource type, but in general it is formed by combining the values of the resource's required parameters with a `:` separator, starting with the more general parameters. Using the example above, assume that the security policy resource has been created with these values: configuration ID: 33673, latest_version: 55, and security policy ID: "XYZ_12345". In this example, the `ID` would be "33673:55:XYZ_12345". To import this resource into your local Terrform state, you would run this command: + +```bash +$ terraform import akamai_appsec_security_policy.security_policy_create 33673:55:PL5_138221 +``` -## Beta Features +## Beta features -Note that the following data sources and resources are currently in Beta, and their behavior or documentation may change in a future release: +NOTE: The following data sources and resources are currently in Beta, and their behavior or documentation might change in a future release: ### Data Sources + * akamai_appsec_advanced_settings_logging + * akamai_appsec_advanced_settings_prefetch + * akamai_appsec_api_endpoints + * akamai_appsec_api_request_constraints + * akamai_appsec_attack_group_actions + * akamai_appsec_attack_group_condition_exception + * akamai_appsec_custom_deny * akamai_appsec_eval + * akamai_appsec_eval_hostnames * akamai_appsec_eval_rule_actions * akamai_appsec_eval_rule_condition_exception + * akamai_appsec_failover_hostnames + * akamai_appsec_hostname_coverage + * akamai_appsec_hostname_coverage_match_targets + * akamai_appsec_hostname_coverage_overlapping * akamai_appsec_ip_geo - * akamai_appsec_rule_actions - * akamai_appsec_rule_condition_exception * akamai_appsec_penalty_box - * akamai_appsec_security_policy_protections * akamai_appsec_rate_policies * akamai_appsec_rate_policy_actions - * akamai_appsec_rate_protections - * akamai_appsec_reputation_protections - * akamai_appsec_reputation_profiles * akamai_appsec_reputation_profile_actions + * akamai_appsec_reputation_profile_analysis + * akamai_appsec_reputation_profiles + * akamai_appsec_rule_actions + * akamai_appsec_rule_condition_exception * akamai_appsec_rule_upgrade_details + * akamai_appsec_security_policy_protections + * akamai_appsec_siem_definitions + * akamai_appsec_siem_settings * akamai_appsec_slow_post * akamai_appsec_slowpost_protections + * akamai_appsec_version_notes * akamai_appsec_attack_group_actions * akamai_appsec_waf_mode - * akamai_appsec_waf_protection - * akamai_appsec_attack_group_condition_exception ### Resources + * akamai_appsec_advanced_settings_logging + * akamai_appsec_advanced_settings_prefetch + * akamai_appsec_api_request_constraints + * akamai_appsec_attack_group_action + * akamai_appsec_attack_group_condition_exception + * akamai_appsec_custom_deny * akamai_appsec_eval * akamai_appsec_eval_rule_action * akamai_appsec_eval_rule_condition_exception * akamai_appsec_ip_geo - * akamai_appsec_rule_condition_exception - * akamai_appsec_rule_action * akamai_appsec_penalty_box - * akamai_appsec_security_policy_protections * akamai_appsec_rate_policy * akamai_appsec_rate_policy_action * akamai_appsec_rate_protection - * akamai_appsec_reputation_protection * akamai_appsec_reputation_profile * akamai_appsec_reputation_profile_action + * akamai_appsec_reputation_profile_analysis + * akamai_appsec_reputation_protection + * akamai_appsec_rule_action + * akamai_appsec_rule_condition_exception * akamai_appsec_rule_upgrade + * akamai_appsec_security_policy_protections + * akamai_appsec_siem_settings * akamai_appsec_slow_post * akamai_appsec_slowpost_protection - * akamai_appsec_attack_group_action + * akamai_appsec_version_notes * akamai_appsec_waf_mode * akamai_appsec_waf_protection - * akamai_appsec_attack_group_condition_exception - diff --git a/docs/guides/get_started_dns_zone.md b/docs/guides/get_started_dns_zone.md index 7e69c60db..2fb9eb26b 100644 --- a/docs/guides/get_started_dns_zone.md +++ b/docs/guides/get_started_dns_zone.md @@ -12,94 +12,74 @@ importing existing zones and recordsets. To get more information about Edge DNS, see: -* [API documentation](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html) -* How-to Guides - * [Official Documentation](https://learn.akamai.com/en-us/products/cloud_security/edge_dns.html) +* Developer - [API documentation](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html). +* User Guide - [Official Documentation](https://learn.akamai.com/en-us/products/cloud_security/edge_dns.html). -## Configure the Terraform Provider -Set up your credential files as described in [Get Started with Akamai APIs](https://developer.akamai.com/api/getting-started), and include authorization for the GTM Config API +## Prerequisites -Next, we need to configure the provider with our credentials. This is done using a provider configuration block. +Before starting with the DNS module, you need to: -1. Create a new folder called `terraform` -1. Inside the new folder, create a new file called `akamai.tf`. -1. Add the provider configuration to your `akamai.tf` file: +1. Complete the tasks in [Akamai: Get Started with the Akamai Terraform Provider](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_provider). +2. Determine whether you want to import an existing DNS zone and records or create new ones. +3. If you're importing an existing DNS configuration, continue with [Import a DNS zone and records](#import-a-dns-zone-and-records). +3. If you're creating a new DNS configuration, continue with [Create a DNS zone +](#create-a-dns-zone) and [Create a DNS record](#create-a-dns-record). -```hcl -provider "akamai" { - dns { - host = "..." - access_token = "..." - client_token = "..." - client_secret = "..." - } -} -``` - -## Prerequisites +## Import a DNS zone and records -To create a zone there are several dependencies you must first meet: +You can migrate an existing Edge DNS zone into your Terraform configuration using either a command line utility or step-by-step construction. -* **Contract ID**: The ID of the contract under which the zone and contained recordsets will live -* **Group ID**: The ID of the group under which the zone and contained recordsets will live +### Import using the command line utility -To import an existing zone and recordsets, you must also know the identifiers or the objects; e.g. zone and recordset names in addition to the prior information. +You can use the [Akamai CLI for Akamai Terraform Provider](https://github.com/akamai/cli-terraform) to generate a configuration for and import an existing Edge DNS zone and its recordsets. With the package, you can generate: -## Retrieving The Contract ID +* a JSON-formatted list of the zone and recordsets. +* a Terraform configuration for the zone and select recordsets. +* a command line script to import all defined resources. -You can fetch your contract ID automatically using the [`akamai_contract` data source](../data-sources/property_contract.md). To fetch the default contract ID no attributes need to be set: +Before using this CLI, keep the following in mind: -```hcl -data "akamai_contract" "default" { +* Download the existing zone configuration and master file to have as a backup and reference during an import. You can download these by using the [Edge DNS Zone Management API](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html) or the Edge DNS app on [Control Center](https://control.akamai.com). +* Terraform limits the characters that can be part of its resource names. During construction of the resource configurations, invalid characters are replaced with underscore , '_'. +* Terraform doesn't provide any state information during import. When you run `plan` and `apply` after an import, Terraform lists discrepencies and reconciles configurations and state. Any discrepencies clear following the first `apply`. +* After first time you run `plan` or `apply`, the `contract` and `group` attributes are updated. +* Run `terraform plan` after importing to validate the generated `tfstate` file. -} -``` +### Import using step-by-step construction -Alternatively, if you have multiple contracts, you can specify the `group` which contains it: +To import using step-by-step construction, complete these tasks: -```hcl -data "akamai_contract" "default" { - group_name = "default" -} -``` +1. Determine how you want to test your Terraform import. For example, you may want to set up your zone and recordset imports in a test environment to familiarize yourself with the provider operation and mitigate any risks to your existing DNS zone configuration. +1. Download the existing zone configuration and master file to have as a backup and reference during an import. You can download these from the [Edge DNS Zone Management API](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html) or from the Edge DNS app on [Control Center](https://control.akamai.com) . +1. Using the zone master file as a reference, create a Terraform configuration representing the existing zone and all contained recordsets. +1. Verify that your Terraform configuration addresses all required attributes and any optional and computed attributes you need. +1. Run `terraform import`. This command imports the existing zone and contained recordsets. The import happens in serial order. +1. Compare the downloaded zone master file with the `terraform.tfstate` file to confirm that the zone and all recordsets are represented correctly. +1. Run `terraform plan` on the configuration. The plan should be empty. If not, correct accordingly and repeat until plan is empty and configuration is in sync with the Edge DNS backend. -You can now refer to the contract ID using the `id` attribute: `data.akamai_contract.default.id`. +## Create a DNS zone -## Retrieving The Group ID +The zone itself is represented by a [`akamai_dns_zone` resource](../resources/dns_zone.md). Add this new resource block to your `akamai.tf` file after the provider block. **Note:** the zone should be the first DNS resource created as it provides operating context for all other recordset resources. -Similarly, you can fetch your group ID automatically using the [`akamai_group` data source](../data-sources/property_group.md). To fetch the default group ID no attributes other than contract need to be set: +To define the entire configuration, we start by opening the resource block and giving the `zone` a name. In this case we’re going to use the name "example." -```hcl -data "akamai_group" "default" { - contract_id = data.akamai_contract.default.id -} -``` +Next, we set the required (`zone`, `type`, `group`, `contract`) and optional (`comment`) arguments for a simpler secondary `type`. -To fetch a specific group, you can specify the `name` argument: +Once done, your `akamai.tf` configuration file should include configuration items such as: -```hcl -data "akamai_group" "default" { - name = "example" - contract_id = data.akamai_contract.default.id -} ``` +terraform { + required_providers { + akamai = { + source = "akamai/akamai" + version = "1.2.0" + } + } +} -You can now refer to the group ID using the `id` attribute: `data.akamai_group.default.id`. - -## Creating a DNS Zone - -The zone itself is represented by a [`akamai_dns_zone` resource](../resources/dns_zone.md). Add this new resource block to your `akamai.tf` file after the provider block. Note: the zone should be the first DNS resource created as it provides operating context for all other recordset resources. - -To define the entire configuration, we start by opening the resource block and giving the zone a name. In this case we’re going to use the name "example". - -Next, we set the required (zone, type, group, contract) and optional (comment) arguments. - -Once you’re done, your zone configuration file should look like this: - -```hcl locals { - section = "default" + section = "default" } provider "akamai" { @@ -113,30 +93,38 @@ data "akamai_group" "default" { contract_id = data.akamai_contract.default.id } -resource "akamai_dns_zone" "example" { - zone = "examplezone.com" # Zone Name - type = "secondary" # Zone type - master = [ "1.2.3.4" ] # Zone master(s) - group = data.akamai_group.default.id # Group ID variable - contract = data.akamai_contract.default.id # Contract ID variable +resource "akamai_dns_zone" "example_com" { + zone = "examplezone.com" # Zone Name + type = "secondary" # Zone type + masters = [ "1.2.3.4" ] # Zone master(s) + group = data.akamai_group.default.id # Group ID variable + contract = data.akamai_contract.default.id # Contract ID variable comment = "example zone demo" } ``` -> **Note:** Notice that we’re using variables from the previous section to reference the group and contract IDs. These will automatically be replaced at runtime by Terraform with the actual values. +> **Note:** Notice the use of variables from the previous section to reference the group and contract IDs. These will be replaced at runtime by Terraform with the actual values. + +### Validate Terraform Zone Configuration and State + +To validate the configuration up to this point, run the following command. The actual commit will come later in the procedure with an apply command. + +``` +$ terraform plan +``` ### Primary Zones -Creating primary zones through Terraform is best performed through the following multi step process. In addition to the Terraform provider, you will need to download and install the Akamai CLI and CLI-Terraform package. +Unlike creating secondary zone types, creating primary zone types is best by following a multi-step process as follows. To complete these steps, you need to download and install the [Akamai CLI](https://developer.akamai.com/cli) and [CLI-Terraform package](https://github.com/akamai/cli-terraform). #### Configure Zone -Create the zone configuration in a new zone configuration file. For this example, use example_primary_zone_com.tf +In addition to `akamai.tf` set with Get Started with the [Akamai Terraform Provider Guide](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_provider), create the zone configuration in a new zone configuration file. For this example, use `example_primary_zone_com.tf`. -Note: Subsequent steps will require the zone config file be named `.tf` with dots replaced by underscores. +**Note:** Subsequent steps will require the zone configuration file be named `.tf` with dots replaced by underscores. Edge DNS will automatically create NS and SOA records. Steps below show how to synchronize these records to the local Terraform state. -Example configuration: +##### Example configuration: -```hcl +``` locals { section = "default" zone = "example_primary_zone.com" @@ -164,15 +152,23 @@ resource "akamai_dns_zone" "primary_example" { } ``` -Run Terraform Apply +**Note:** Referencing items in the locals block is done so with a singular `local` prefix such as `local.section`. Because Terraform references variables in all `.tf` files, the locals and provider blocks may not necessary in this zone file. + +### Validate Terraform Zone Configuration and State + +To validate the configuration up to this point, run the following command. The actual commit will come later in the procedure with an apply command. + +``` +$ terraform plan +``` -Note: Creating a primary zone has the side effect of creating both initial SOA and NS records. Without these two records, the zone can not be managed. +**Note:** You can run `terraform plan` many times. -#### Adding Zone SOA and NS Records To TF Configuration +### Adding Zone SOA and NS Records To TF Configuration -The zone's top level SOA and NS records now need to be added to the Terraform configuration. These records have been created and pre populated in the Akamai DNS Infrastructure. +Creating a primary zone has the side effect of creating both initial SOA and NS records. Without these two recordsets, the zone cannot be managed. Using the CLI-Terraform CLI package, the zone's top level SOA and NS records now need to be added to the Terraform configuration as follows. -Use CLI-Terraform to add the SOA and NS records by performing the following steps: +#### Create a List of Zone Recordsets First, create a list of the zone's current recordsets. @@ -180,7 +176,7 @@ First, create a list of the zone's current recordsets. $ akamai terraform create-zone example_primary_zone.com --resources ``` -The file, example_primary_zone_com_resources.json, will be generated with the following content: +The command will generate a file, `example_primary_zone_com_resources.json`, with the following content: ``` { @@ -194,13 +190,15 @@ The file, example_primary_zone_com_resources.json, will be generated with the fo } ``` -Next, update the Terraform Zone configuration file using the previously generated JSON as input. +#### Update the Terraform Zone Configuration File + +Next, update the Terraform Zone configuration file using the previously generated JSON file as input and the following command. ``` $ akamai terraform create-zone example_primary_zone.com --createconfig ``` -The zone configuration file, example_primary_zone_com.tf, will be updated with the resulting content: +The zone configuration file, `example_primary_zone_com.tf`, will be updated with the resulting content: ``` resource "akamai_dns_zone" "primary_example" { @@ -233,21 +231,23 @@ resource "akamai_dns_record" "example_primary_zone_com_example_primary_zone_com_ ttl = 86400 } ``` -Note: Name server targets have been masked. Also, a default dnsvars.tf file is generated. It can be ignored, deleted or used. +**Note:** Name server targets have been masked. Also, a default `dnsvars.tf` file is generated. It can be ignored, deleted or used. Other Terraform configuration files can reference variables in this file with a macro such as "${dnsvar.zone}". + +#### Generate a Resource Import Script -Next, generate zone resources import script using previously generated output. +Next, generate a zone resources import script using previously generated output. ``` $ akamai terraform create-zone example_primary_zone.com --importscript ``` -The file example_primary_zone.com_resource_import.script is generated with the following content: +The file `example_primary_zone.com_resource_import.script` is generated with the following content: -```bash +``` terraform init -terraform import akamai_dns_zone.egl_clidns_primary_test_com egl_clidns_primary_test.com -terraform import akamai_dns_record.egl_clidns_primary_test_com_egl_clidns_primary_test_com_NS egl_clidns_primary_test.com#egl_clidns_primary_test.com#NS -terraform import akamai_dns_record.egl_clidns_primary_test_com_egl_clidns_primary_test_com_SOA egl_clidns_primary_test.com#egl_clidns_primary_test.com#SOA +terraform import akamai_dns_zone.clidns_primary_test_com clidns_primary_test.com +terraform import akamai_dns_record.clidns_primary_test_com_clidns_primary_test_com_NS clidns_primary_test.com#clidns_primary_test.com#NS +terraform import akamai_dns_record.clidns_primary_test_com_clidns_primary_test_com_SOA clidns_primary_test.com#clidns_primary_test.com#SOA ``` Next, edit the script file and remove the line `terraform import akamai_dns_zone.egl_clidns_primary_test_com egl_clidns_primary_test.com` as the zone does not need to be imported. @@ -262,13 +262,15 @@ $ ./example_primary_zone.com_resource_import.script The Terraform configuration and state will now contain the zone's SOA and NS Records with values consistent with the Akamai DNS Infrastructure. -#### Validate Terraform Zone Configuration and State +### Validate Terraform Zone Configuration and State + +To validate the configuration up to this point, run the following command. The actual commit will come later in the procedure with an apply command. ``` $ terraform plan ``` -## Creating a DNS Record +## Create a DNS record The recordset itself is represented by a [`akamai_dns_record` resource](../resources/dns_record.md). Add this new block to your `akamai.tf` file after the provider block. @@ -276,9 +278,9 @@ To define the entire configuration, we start by opening the resource block and g Next, we set the required (zone, recordtype, ttl) and any optional/required arguments based on recordtype. Required fields for each record type are itemized in [`akamai_dns_record` resource](../resources/dns_record.md). -Once you’re done, your record configuration should look like this: +Once complete, your record configuration should look like this: -```hcl +``` resource "akamai_dns_record" "example_a_record" { zone = akamai_dns_zone.example.zone target = ["10.0.0.2"] @@ -288,37 +290,25 @@ resource "akamai_dns_record" "example_a_record" { } ``` -## Initialize the Provider +## Validate Terraform Zone Configuration and State -Once you have your configuration complete, save the file. Then switch to the terminal to initialize Terraform using the command: +To validate the configuration up to this point, run the following command. The actual commit will come later in the procedure with an apply command. -```bash -$ terraform init ``` - -This command will install the latest version of the Akamai Provider, as well as any other providers necessary (such as the local provider). To update the Akamai Provider version after a new release, simply run `terraform init` again. - -## Test Your Configuration - -To test your configuration, use `terraform plan`: - -```bash $ terraform plan ``` -This command will make Terraform create a plan for the work it will do based on the configuration file. This will not actually make any changes and is safe to run as many times as you like. - ## Apply Changes -To actually create our zone and recordset, we need to instruct Terraform to apply the changes outlined in the plan. To do this, in the terminal, run the command: +To actually create our zone and recordset, we need to instruct Terraform to apply the changes outlined in the plan. To do this, run the command: -```bash +``` $ terraform apply ``` -Once this completes your zone and recordset will have been created. You can verify this in [Akamai Control Center](https://control.akamai.com). +Once this completes, your zone and recordset will have been created. You can verify this in [Akamai Control Center](https://control.akamai.com). -## Import +## Import Records Existing DNS resources may be imported using one of the following formats: @@ -327,15 +317,29 @@ $ terraform import akamai_dns_zone.{{zone resource name}} {{edge dns zone name}} $ terraform import akamai_dns_record.{{record resource name}} {{edge dns zone name}}#{{edge dns recordset name}}#{{record type}} ``` -[Migrating A DNS Zone](../guides/faq.md#migrating-an-edge-dns-zone-and-records-to-terraform) discusses DNS resource import in more detail. +## How you can use the DNS module + +These sections include information on different ways to use the Akamai's Terraform DNS module: + +* [Working With MX Records](#working-with-mx-records) +* [Important Behavior Considerations](#important-behavior-considerations) +* [Primary Zone Partially Created](#primary-zone-partially-created) ## Working With MX Records -MX Record resource configurations may be instantiated in a number of different forms. These forms consist of: +MX Record resource configurations may be instantiated in three different forms: + +1. Coupling Priority and Host. +2. Assigning Priority to Hosts via Variables. +3. Instance Generation. + +### Coupling Priority and Host -### Coupling Priority an Host +With this configuration style, each target entry includes both the priority and host. The following configuration will produce a recordset rdata value of: -With this configuration style, each target entry includes both the priority and host. The following configuration +``` +["0 smtp-0.example.com.", "10 smtp-1.example.com."] +``` ``` resource "akamai_dns_record" "mx_record_self_contained" { @@ -346,16 +350,15 @@ resource "akamai_dns_record" "mx_record_self_contained" { ttl = 300 } ``` -will produce a recordset rdata value of - -``` -["0 smtp-0.example.com.", "10 smtp-1.example.com."] -``` ### Assigning Priority to Hosts via Variables -With this configuration style, a number of hosts will be defined in the target field as a list. A starting priority and priority_increment are also defined. The provider -will construct the rdata values by incrementally pairing and incrementing the priority by the priority_increment. For example, the following configuration +With this configuration style, a number of hosts will be defined in the target field as a list. A starting `priority` and `priority_increment` are also defined. The provider +will construct the rdata values by incrementally pairing and incrementing the `priority` by the `priority_increment`. For example, the following configuration will produce a recordset rdata value of: + +``` +["10 smtp-1.example.com.", "20 smtp-2.example.com.", "30 smtp-3.example.com."] +``` ``` resource "akamai_dns_record" "mx_record_pri_increment" { @@ -368,15 +371,14 @@ resource "akamai_dns_record" "mx_record_pri_increment" { ttl = 900 } ``` -will produce a recordset rdata value of - -``` -["10 smtp-1.example.com.", "20 smtp-2.example.com.", "30 smtp-3.example.com."] -``` ### Instance Generation -With this configuration style, a number of host instances can be generated by using Terraform's count or for/each construct. For example, the following configuration +With this configuration style, a number of host instances can be generated using Terraform's count or for/each construct. For example, the following configuration will produce three distinct resource instances, each with a single target and priority, and an aggregated recordset rdata value of: + +``` +["0 smtp-0.example.com.", "10 smtp-1.example.com.", "20 smtp-2.example.com."] +``` ``` resource "akamai_dns_record" "mx_record_instances" { @@ -389,17 +391,12 @@ resource "akamai_dns_record" "mx_record_instances" { priority = count.index*10 } ``` -will produce three distinct resource instances, each with a single target and priority, and an aggregated recordset rdata value of - -``` -["0 smtp-0.example.com.", "10 smtp-1.example.com.", "20 smtp-2.example.com."] -``` ## Important Behavior Considerations -* Concurrrent modifications thru the Terraform provider and the UI may result in configuration drift and require manual intervention to reconcile. This issue is particularly a concern for MX records. +* Concurrent and independent modifications through the Terraform provider and Control Center UI may result in configuration drift and require manual intervention to reconcile the local Terraform state. This issue is particularly a concern for MX records. * Deletion of a record resource with multiple instances or deletion of a single instance, will result in the entire remote recordset resource being removed. -* Record configurations and state include a computed record_sha field. This field is used represent the current resource state as well as to compare local MX record configuration with the remote configuration. This field will not exist in upgraded configurations. As such, doing a plan on an existing MX record may result in the following informational message which can be ignored. +* Record configurations and state include a computed `record_sha` field that represents the current resource state to compare the local and remote MX record configurations. This field will not exist in upgraded configurations. As such, doing a plan on an existing MX record may result in the following message to ignore. ``` No changes. Infrastructure is up-to-date. @@ -408,3 +405,11 @@ This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed. ``` + +## Primary Zone Partially Created + +While it's rare, sometimes a primary zone is only partially created on the Akamai backend. For example, a network error happens and while the zone was created, the SOA and NS records were not. + +Any attempt to manage or administer recordsets in the zone will fail. To resolve this issue, you have to manually create the SOA and NS records before you can manage the configuration. + +You can create these records from the Edge DNS application available from [Akamai Control Center](https://control.akamai.com). You also have the option of using the [Akamai CLI for Edge DNS](https://github.com/akamai/cli-dns). diff --git a/docs/guides/get_started_gtm_domain.md b/docs/guides/get_started_gtm_domain.md index e0258051e..ed0368f5b 100644 --- a/docs/guides/get_started_gtm_domain.md +++ b/docs/guides/get_started_gtm_domain.md @@ -7,98 +7,67 @@ description: |- # Get Started with GTM Domain Administration -The Akamai Provider for Terraform provides you the ability to automate the creation, deployment, and management of GTM domain configuration and administration; as well as importing existing domains and contained objects. +The Akamai Provider for Terraform provides you the ability to automate the creation, deployment, and management of Global Traffic Management (GTM) domain configuration and administration; as well as importing existing domains and contained objects. To get more information about Global Traffic Management, see: -* [API documentation](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html) -* How-to Guides - * [Official Documentation](https://learn.akamai.com/en-us/products/web_performance/global_traffic_management.html) +* Developer - [API documentation](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html) +* User Guide - [Official Documentation](https://learn.akamai.com/en-us/products/web_performance/global_traffic_management.html) -## Configure the Terraform Provider +## Prerequisites -Set up your credential files as described in [Get Started with Akamai APIs](https://developer.akamai.com/api/getting-started), and include authorization for the GTM Config API +Before starting with the DNS module, you need to: -Next, we need to configure the provider with our credentials. This is done using a provider configuration block. +1. Complete the tasks in [Akamai: Get Started with the Akamai Terraform Provider](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_provider). You should have an API client and a valid `akamai.tf` Terraform configuration at this point before adding the GTM module configuration. +2. Determine whether you want to import an existing DNS zone and records or create new ones. +3. If you're importing an existing GTM domain, continue with [Import a GTM domain](#import-a-gtm-domain). +3. If you're creating a new GTM domain, continue with [Create a GTM domain +](#create-a-gtm-domain). -1. Create a new folder called `terraform` -1. Inside the new folder, create a new file called `akamai.tf`. -1. Add the provider configuration to your `akamai.tf` file: +## Import a GTM domain -```hcl -provider "akamai" { - edgerc = "~/.edgerc" - config_section = "default" - gtm { - host = "..." - access_token = "..." - client_token = "..." - client_secret = "..." - } -} -``` +You can migrate an existing GTM domain into your Terraform configuration using either a command line utility or step-by-step construction. -## Prerequisites +### Import using the command line utility -To create a domain there are several dependencies you must first meet: +You can use the [Akamai CLI for Akamai Terraform Provider](https://github.com/akamai/cli-terraform) to generate a configuration for and import an existing GTM domain. With the package, you can generate: -* **Contract ID**: The ID of the contract under which the domain and contained objects will live -* **Group ID**: The ID of the group under which the domain and contained objects will live +* a JSON-formatted list of all domain objects. +* a Terraform configuration for the domain and contained objects. +* a command line script to import all defined resources. -To import an existing domain and contained objects, you must also know the identifiers or the objects; e.g. domain name, datacenter id or object name in addition to the prior information. +Before using this CLI, keep the following in mind: -## Retrieving The Contract ID +* Download the existing GTM domain configuration to have as a backup and reference during an import. You can download these by using the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html) or the GTM app on [Control Center](https://control.akamai.com). +* Terraform limits the characters that can be part of its resource names. During construction of the resource configurations, invalid characters are replaced with underscore , '_'. +* Terraform doesn't provide any state information during import. When you run `plan` and `apply` after an import, Terraform lists discrepencies and reconciles configurations and state. Any discrepencies clear following the first `apply`. +* After first time you run `plan` or `apply`, the `contract`, `group`, and `wait_on_complete` attributes are updated. +* Run `terraform plan` after importing to validate the generated `tfstate` file. -You can fetch your contract ID automatically using the [`akamai_contract` data source](../data-sources/property_contract.md). To fetch the default contract ID no attributes need to be set: - -```hcl -data "akamai_contract" "default" { - -} -``` +### Import using step-by-step construction -Alternatively, if you have multiple contracts, you can specify the `group` which contains it: +To import using step-by-step construction, complete these tasks: -```hcl -data "akamai_contract" "default" { - group_name = "default" -} -``` +1. Determine how you want to test your Terraform import. For example, you may want to set up your zone and recordset imports in a test environment to familiarize yourself with the provider operation and mitigate any risks to your existing DNS zone configuration. +1. Download the existing domain configuration and master file to have as a backup and reference during an import. You can download these from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html) or from the GTM app on [Control Center](https://control.akamai.com) . +1. Using the domain download as a reference, create a Terraform configuration representing the existing domain and all contained GTM objects. +1. Verify that your Terraform configuration addresses all required attributes and any optional and computed attributes you need. +1. Run `terraform import`. This command imports the existing domain and contained objects one at a time based on the order in the configuration. +1. Compare the downloaded domain file with the `terraform.tfstate` file to confirm that the domain and all objects are represented correctly. +1. Run `terraform plan` on the configuration. The plan should be empty. If not, correct accordingly and repeat until plan is empty and configuration is in sync with the Edge DNS backend.### Via Step By Step Construction +1. Run `terraform plan` on the configuration. The plan should be empty. If not, correct accordingly and repeat until plan is empty and configuration is in sync with the GTM Backend. -You can now refer to the contract ID using the `id` attribute: `data.akamai_contract.default.id`. +## Create a GTM Domain -## Retrieving The Group ID +The Domain itself is represented by a [`akamai_gtm_domain` resource](../resources/gtm_domain.md). Add this new resource block to your `akamai.tf` file after the provider block. **Note:** the domain must be the first GTM resource created as it provides operating context for all other contained objects. -Similarly, you can fetch your group ID automatically using the [`akamai_group` data source](../data-sources/property_group.md). To fetch the default group ID no attributes other than contract need to be set: +To define the entire configuration, we start by opening the resource block and giving the domain a `name`. In this case, we’re going to use the name "example". -```hcl -data "akamai_group" "default" { - contract_id = data.akamai_contract.default.id -} -``` +Next, we set the required (`name`, `type`) and optional (`group_id`, `contract_id`, `email_notification_list`, `comment`) arguments. -To fetch a specific group, you can specify the `name` argument: +Once you’re done, your Domain configuration should look like this: -```hcl -data "akamai_group" "default" { - name = "example" - contract_id = data.akamai_contract.default.id -} ``` - -You can now refer to the group ID using the `id` attribute: `data.akamai_group.default.id`. - -## Creating a GTM Domain - -The domain itself is represented by an [`akamai_gtm_domain` resource](../resources/gtm_domain.md). Add this new resource block to your `akamai.tf` file after the provider block. Note: the domain must be the first GTM resource created as it provides operating context for all other contained objects. - -To define the entire configuration, we start by opening the resource block and giving the domain a name. In this case we’re going to use the name "example". - -Next, we set the required (domain, type) and optional (group ID, contract ID, email list, comment) arguments. - -Once you’re done, your domain configuration should look like this: - -```hcl resource "akamai_gtm_domain" "example" { name = "example.akadns.net" # Domain Name type = "weighted" # Domain type @@ -108,19 +77,19 @@ resource "akamai_gtm_domain" "example" { comment = "example domain demo" } ``` -> **Note:** Notice that we’re using variables from the previous section to reference the group and contract IDs. These will automatically be replaced at runtime by Terraform with the actual values. +> **Note:** Notice the use of variables from the previous section to reference the group and contract IDs. These will be replaced at runtime by Terraform with the actual values. -## Creating a GTM Datacenter +## Create a GTM Datacenter -The datacenter itself is represented by an [`akamai_gtm_datacenter` resource](../resources/gtm_datacenter.md). Add this new block to your `akamai.tf` file after the provider block. +The Datacenter itself is represented by a [`akamai_gtm_datacenter` resource](../resources/gtm_datacenter.md). Add this new block to your `akamai.tf` file after the provider block. -To define the entire configuration, we start by opening the resource block and give it a name. In this case we’re going to use the name "example_dc". +To define the entire configuration, we start by opening the resource block and giving it a name. In this case, we’re going to use the name "example_dc". -Next, we set the required (domain name) and optional (nickname) arguments. +Next, we set the required (`domain` name) and optional (`nickname`) arguments. -Once you’re done, your datacenter configuration should look like this: +Once done, your Datacenter configuration should look like this: -```hcl +``` resource "akamai_gtm_datacenter" "example_dc" { domain = akamai_gtm_domain.example.name # domain nickname = "datacenter_1" # Datacenter Nickname @@ -128,17 +97,17 @@ resource "akamai_gtm_datacenter" "example_dc" { } ``` -## Creating a GTM Property +## Create a GTM Property -The property itself is represented by an [`akamai_gtm_property` resource](../resources/gtm_property.md). Add this new block to your `akamai.tf` file after the provider block. +The Property itself is represented by a [`akamai_gtm_property` resource](../resources/gtm_property.md). Add this new block to your `akamai.tf` file after the provider block. -To define the entire configuration, we start by opening the resource block and give it a name. In this case we’re going to use the name "example_prop". +To define the entire configuration, we start by opening the resource block and giving it a name. In this case, we’re going to use the name "example_prop". -Next, we set the required (domain name, property name, property type, traffic_targets, liveness_tests, score_aggregation_type, handout_limit, handout_mode) and optional (failover_delay, failback_delay) arguments. +Next, we set the required (`domain` name, property `name`, property `type`, `traffic_target`s, `liveness_test`s, `score_aggregation_type`, `handout_limit`, `handout_mode`) and optional (`failover_delay`, `failback_delay`) arguments. -Once you’re done, your property configuration should look like this: +Once you’re done, your Property configuration should look like this: -```hcl +``` resource "akamai_gtm_property" "example_prop" { domain = akamai_gtm_domain.example.name # domain name = "example_prop_1" # Property Name @@ -193,7 +162,7 @@ resource "akamai_gtm_property" "example_prop" { Once you have your configuration complete, save the file. Then switch to the terminal to initialize Terraform using the command: -```bash +``` $ terraform init ``` @@ -203,23 +172,23 @@ This command will install the latest version of the Akamai Provider, as well as To test your configuration, use `terraform plan`: -```bash +``` $ terraform plan ``` -This command will make Terraform create a plan for the work it will do based on the configuration file. This will not actually make any changes and is safe to run as many times as you like. +This command will make Terraform create a plan for the work set by the configuration file. This will not actually make any changes and is safe to run as many times. ## Apply Changes -To actually create our domain, datacenter and property;, we need to instruct Terraform to apply the changes outlined in the plan. To do this, in the terminal, run the command: +To actually create our Domain, Datacenter and Property, we need to instruct Terraform to apply the changes outlined in the plan. To do this, run the command: -```bash +``` $ terraform apply ``` -Once this completes your domain, datacenter and property will have been created. You can verify this in [Akamai Control Center](https://control.akamai.com) or via the [Akamai CLI](https://developer.akamai.com/cli). +Once this completes your Domain, Datacenter and Property will have been created. You can verify this in [Akamai Control Center](https://control.akamai.com) or via the [Akamai CLI](https://developer.akamai.com/cli). -## Import +## Import Existing GTM Resource Existing GTM resources may be imported using the following formats: @@ -233,5 +202,6 @@ $ terraform import akamai_gtm_geomap.{{geomap resource name}} {{gtm domain name} $ terraform import akamai_gtm_asmap.{{asmap resource name}} {{gtm domain name}}:{{gtm asmap name}} ``` -[Migrating A GTM Domain](../guides/faq.md#migrating-a-gtm-domain-and-contained-objects-to-terraform) discusses GTM resource import in more detail. +## GTM field status when running plan and apply +When using `terraform plan` or `terraform apply`, Terraform presents fields defined in the configuration and all defined resource fields. Fields are either required, optional, or computed as specified in each resource description. Default values for fields will display if not explicitly configured. In many cases, the default will be zero, empty string, or empty list depending on the type. These default or empty values are informational and not included in resource updates. diff --git a/docs/guides/get_started_provider.md b/docs/guides/get_started_provider.md index 08129c3eb..e2cc4c004 100644 --- a/docs/guides/get_started_provider.md +++ b/docs/guides/get_started_provider.md @@ -10,7 +10,7 @@ description: |- If you've set up Akamai APIs before, some of the Akamai Provider setup tasks will look familiar. You'll need to create Akamai API clients for each of the modules you'll be using, and retrieve IDs for your contracts -and groups. Other tasks, like setting up your `akamai.tf` file, are very +and groups. Other tasks, like setting up your `akamai.tf` file, are specific to Terraform. Complete the tasks in this guide when setting up the Akamai @@ -62,10 +62,7 @@ Now that you made some decisions, you need to set up a Terraform configuration f ## Create Akamai API clients -Create an Akamai API client with the right permissions and valid -credentials to authenticate your Akamai Provider files. Your Akamai API -client needs read-write permission to the APIs associated with the -Akamai Provider modules you're using, like DNS or Provisioning. +Create an Akamai API client with the right permissions and valid credentials to authenticate your Akamai Provider files. Your Akamai API client needs read-write permission to the APIs associated with the Akamai Provider modules you're using, like DNS or Provisioning. Once you set up the API clients, you add credential information from those clients to your `akamai.tf` file. @@ -73,33 +70,25 @@ See the [Authenticate the Akamai Terraform Provider](../guides/akamai_provider_a guide for details. Once you're done authenticating, come back here to complete the Akamai Provider setup. +**Note:** Depending on the select contract and group, the Edge DNS and GTM modules may depend on both Property Manager APIs as well. If so, be sure to include a PAPI authorization to the Edge DNS and GTM API Clients. + ## Retrieve contract and group IDs You'll need contract and group IDs to use most Akamai Provider modules. You can retrieve these IDs through the [`akamai_contract`](../data-sources/property_contract.md) and -[`akamai_group`](../data-sources/property_group.md) data sources, which require read access to the Property -Manager API. You can also get this information from the Contracts app in Akamai +[`akamai_group`](../data-sources/property_group.md) data sources, which require read access to the Property Manager API. You can also get this information from the Contracts app in Akamai Control Center, or by using other Akamai APIs or CLIs. ### Retrieve contract IDs with akamai_contract -You can get your contract ID automatically using the [`akamai_contract` data source](../data-sources/property_contract.md). This data source requires access to the Property Manager (PAPI) API service. See [Set up your API clients](../guides/akamai_provider_auth.md#set-up-your-api-clients) +You can get your contract ID automatically using the [`akamai_contract` data source](../data-sources/property_contract.md). This data source requires access to the Property Manager (PAPI) API service. See [Set up your API clients](../guides/akamai_provider_auth.md#set-up-your-api-clients). -To retrieve the default contract you need to enter a group name or ID no attributes need to be set: +To retrieve the default contract, you need to enter a group name or ID. No attributes need to be set: ```hcl data "akamai_contract" "default" { group_name = "example group name" - -} -``` - -Alternatively, if you have multiple contracts, you can specify the `group` that contains it: - -```hcl -data "akamai_contract" "default" { - group_name = "default" } ``` @@ -136,11 +125,9 @@ You can now refer to the group ID using the `id` attribute: `data.akamai_group.d ## Set up your Akamai configurations in Terraform -You're now ready to import existing configurations or create new ones -from scratch. +You're now ready to import existing configurations or create new ones from scratch. -At this point in the setup, you should refer to the guides for the -Akamai modules you're using: +At this point in the setup, you should refer to the guides for the Akamai modules you're using: | **Module** | **Guide** | |------------|------------| @@ -151,9 +138,7 @@ Akamai modules you're using: | Property Manager (Provisioning and Common modules) | [Get Started with Property Provisioning](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_property) | -> **Note** Both Terraform and the Akamai Terraform CLI package come -pre-installed in the Akamai Development Environment. Get more details in -our [[installation -Instructions](https://developer.akamai.com/blog/2020/05/26/set-development-environment). +pre-installed in the Akamai Development Environment. See [Set Up a Development Environment](https://developer.akamai.com/blog/2020/05/26/set-development-environment) for more information. Once you're done with the module-level setup, continue with the next sections to initialize and test the Akamai Provider. diff --git a/docs/index.md b/docs/index.md index f2f340977..417846412 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,7 +14,7 @@ Traffic Management configurations. !> Version 1.0.0 of the Akamai Terraform Provider is a major release that's currently available for the Provisioning module. Before upgrading, you need to make changes to some of your Provisioning resources and data sources. See the [migration guide](guides/1.0_migration.md) for details. -Last updated: January 2021. +Last updated: February 2021. ## Migrate to the newest version @@ -70,9 +70,14 @@ If you're new to Terraform, here are some links you might find helpful: ## Available guides -* [Frequently Asked Questions](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/faq) +Here's a list of the guides for the Akamai Provider in the general order you might use them: + +* [Get Started with the Akamai Terraform Provider](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_provider) +* [Authenticate the Akamai Terraform Provider](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/akamai_provider_auth) +* [Akamai Terraform Provider: 1.0.0 Migration Guide](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/1.0_migration) +* [Get Started with the Identity and Access Management Module](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_iam.md) +* [Get Started with the Provisioning Module](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_property) +* [Get Started with Application Security](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_appsec) * [Get Started with DNS Zone Administration](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_dns_zone) * [Get Started with GTM Domain Administration](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_gtm_domain) -* [Get Started with the Identity and Access Management Module](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_iam.md) -* [Get Started with the Provisioning Module](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/get_started_property) * [Appendix](https://registry.terraform.io/providers/akamai/akamai/latest/docs/guides/appendix) diff --git a/docs/resources/appsec_activations.md b/docs/resources/appsec_activations.md index 061ea12eb..5109da108 100644 --- a/docs/resources/appsec_activations.md +++ b/docs/resources/appsec_activations.md @@ -34,6 +34,10 @@ resource "akamai_appsec_activations" "activation" { ``` +## Argument Reference + +The following arguments are supported: + * `config_id` - (Required) The ID of the security configuration to use. * `version` - (Required) The version number of the security configuration to use. diff --git a/docs/resources/appsec_advanced_settings_logging.md b/docs/resources/appsec_advanced_settings_logging.md new file mode 100644 index 000000000..ff74bfdec --- /dev/null +++ b/docs/resources/appsec_advanced_settings_logging.md @@ -0,0 +1,59 @@ +--- +layout: "akamai" +page_title: "Akamai: AdvancedSettingsLogging" +subcategory: "Application Security" +description: |- + AdvancedSettingsLogging +--- + +# resource_akamai_appsec_advanced_settings_logging + +The `resource_akamai_appsec_advanced_settings_logging` resource allows you to enable, disable, or update HTTP header logging settings for a configuration. This operation applies at the configuration level, and therefore applies to all policies within a configuration. You may override these settings for a particular policy by specifying the policy using the security_policy_id parameter. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to set the logging settings +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +resource "akamai_appsec_advanced_settings_logging" "logging" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + logging = file("${path.module}/logging.json") +} + +// USE CASE: user wants to override the logging settings for a security policy +resource "akamai_appsec_advanced_settings_logging" "policy_logging" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + logging = file("${path.module}/logging.json") +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `logging` - (Required) The logging settings to apply ([format](https://developer.akamai.com/api/cloud_security/application_security/v1.html#puthttpheaderloggingforaconfiguration)). + +* `security_policy_id` - (Optional) The ID of a specific security policy to which the logging settings should be applied. If not supplied, the indicated settings will be applied to all policies within the configuration. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* None + diff --git a/docs/resources/appsec_advanced_settings_prefetch.md b/docs/resources/appsec_advanced_settings_prefetch.md new file mode 100644 index 000000000..d62377dd1 --- /dev/null +++ b/docs/resources/appsec_advanced_settings_prefetch.md @@ -0,0 +1,58 @@ +--- +layout: "akamai" +page_title: "Akamai: AdvancedSettingsPrefetch" +subcategory: "Application Security" +description: |- + AdvancedSettingsPrefetch +--- + +# resource_akamai_appsec_advanced_settings_prefetch + +The `resource_akamai_appsec_advanced_settings_prefetch` resource allows you to enable inspection of internal requests (those between your origin and Akamai’s servers) for file types that you specify. You can also apply rate controls to prefetch requests. This operation applies at the configuration level. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to set the prefetch settings +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +resource "akamai_appsec_advanced_settings_prefetch" "prefetch" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + enable_app_layer = false + all_extensions = true + enable_rate_controls = false + extensions = var.extensions +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `enable_app_layer` - (Required) Whether to enable prefetch requests. + +* `all_extensions` - (Required) Whether to enable prefetch requests for all extensions. + +* `enable_rate_controls` - (Required) Whether to enable prefetch requests for rate controls. + +* `extensions` - (Required) The specific extensions for which to enable prefetch requests. If `all_extensions` is True, `extensions` must be an empty list. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* None + diff --git a/docs/resources/appsec_api_request_constraints.md b/docs/resources/appsec_api_request_constraints.md new file mode 100644 index 000000000..ea78ec3cf --- /dev/null +++ b/docs/resources/appsec_api_request_constraints.md @@ -0,0 +1,62 @@ +--- +layout: "akamai" +page_title: "Akamai: ApiRequestConstraints" +subcategory: "Application Security" +description: |- + ApiRequestConstraints +--- + +# resource_akamai_appsec_api_request_constraints + +The `resource_akamai_appsec_api_request_constraints` resource allows you to update what action to take when the API request constraint triggers. This operation modifies an individual API constraint action. To use this operation, use the `akamai_appsec_api_endpoints` data source to list one or all API endpoints, and use the ID of the selected endpoint. Use the `action` paameter to specify how the alert should be handled. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to set the api request constraints action +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_api_endpoints" "api_endpoint" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + name = var.api_endpoint_name +} + +resource "akamai_api_request_constraints" "api_request_constraints" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + api_endpoint_id = data.akamai_appsec_api_endpoints.api_endpoint.id + action = "alert" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `security_policy_id` - (Required) The ID of the security policy to use. + +* `api_endpoint_id` - (Optional) The ID of the API endpoint to use. If not supplied, the request constraint action will be updated for all APIs. + +* `action` - (Required) The action to assign to API request constraints: either `alert`, `deny`, or `none`. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `output_text` - A tabular display of the API request constraint information. + diff --git a/docs/resources/appsec_attack_group_condition_exception.md b/docs/resources/appsec_attack_group_condition_exception.md index 2898882be..577a187ed 100644 --- a/docs/resources/appsec_attack_group_condition_exception.md +++ b/docs/resources/appsec_attack_group_condition_exception.md @@ -44,8 +44,7 @@ The following arguments are supported: * `attack_group` - The attack group to use. -* `condition_exception` - (Required) The name of a file containing a JSON-formatted description of the conditions and exceptions to use ([format](https://developer.akamai.com/api/cloud_security/application_security/v1.html#putattackgroupconditionexception)) - +* `condition_exception` - (Required) The name of a file containing a JSON-formatted description of the conditions and exceptions to use ([format](https://developer.akamai.com/api/cloud_security/application_security/v1.html#putattackgroupconditionexception)). ## Attributes Reference diff --git a/docs/resources/appsec_bypass_network_lists.md b/docs/resources/appsec_bypass_network_lists.md new file mode 100644 index 000000000..082919037 --- /dev/null +++ b/docs/resources/appsec_bypass_network_lists.md @@ -0,0 +1,48 @@ +--- +layout: "akamai" +page_title: "Akamai: BypassNetworkLists" +subcategory: "Application Security" +description: |- + BypassNetworkLists +--- + +# akamai_appsec_bypass_network_lists + +Use the `akamai_appsec_bypass_network_lists` resource to update which network lists to use in the bypass network lists settings. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to update bypass network lists used in a Security Configuration version +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} +resource "akamai_appsec_bypass_network_lists" "bypass_network_lists" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + bypass_network_list = ["id1","id2"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `bypass_network_list` - (Required) A list containing the IDs of the network lists to use. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `output_text` - A tabular display showing the updated list of network list IDs. + diff --git a/docs/resources/appsec_configuration.md b/docs/resources/appsec_configuration.md new file mode 100644 index 000000000..ef05f7ef0 --- /dev/null +++ b/docs/resources/appsec_configuration.md @@ -0,0 +1,69 @@ +--- +layout: "akamai" +page_title: "Akamai: Configuration" +subcategory: "Application Security" +description: |- + Configuration +--- + +# resource_akamai_appsec_configuration + +The `resource_akamai_appsec_configuration` resource allows you to create a new WAP or KSD security configuration. KSD security configurations start out empty, and WAP configurations are created with preset values. The contract you pass in the request body determines which product you use. You can edit the default settings included in the WAP configuration, but you’ll need to run additional operations in this API to select specific protections for KSD. Your KSD configuration needs match targets and protection settings before it can be activated. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to create a new config +data "akamai_appsec_contract_groups" "contract_groups" { +} + +data "akamai_appsec_selectable_hostnames" "selectable_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +resource "akamai_appsec_configuration" "create_config" { + name = var.name + description = var.description + contract_id= data.akamai_appsec_contract_groups.contract_groups.default.contract_id + group_id = data.akamai_appsec_contract_groups.contract_groups.default.group_id + host_names = data.akamai_appsec_selectable_hostnames.selectable_hostnames.hostnames +} + +output "create_config_id" { + value = akamai_appsec_configuration.create_config.config_id +} + +output "create_config_version" { + value = akamai_appsec_configuration.create_config.version +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name`- (Required) The name to be assigned to the configuration. + +* `description` - (Required) A description of the configuration. + +* `contract_id` - (Required) The contract ID of the configuration. + +* `group_id` - (Required) The group ID of the configuration> + +* `hostnames` - (Required) The list of hostnames protected by this security configuration. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `config_id` - (Required) The ID of the security configuration. + +* `version` - (Required) The latest version of the security configuration. + diff --git a/docs/resources/appsec_configuration_clone.md b/docs/resources/appsec_configuration_clone.md new file mode 100644 index 000000000..7e85be881 --- /dev/null +++ b/docs/resources/appsec_configuration_clone.md @@ -0,0 +1,82 @@ +--- +layout: "akamai" +page_title: "Akamai: ConfigurationClone" +subcategory: "Application Security" +description: |- + ConfigurationClone +--- + +# resource_akamai_appsec_configuration_clone + +The `resource_akamai_appsec_configuration_clone` resource allows you to create a new version of a given security configuration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to clone a new configuration from an existing one +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +// USE CASE: user wants to see contract group details in an account +data "akamai_appsec_contracts_groups" "contracts_groups" { + contractid = var.contractid + groupid = var.groupid +} + +data "akamai_appsec_selectable_hostnames" "selectable_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +resource "akamai_appsec_configuration_clone" "clone_config" { + create_from_config_id = data.akamai_appsec_configuration.configuration.config_id + create_from_version = data.akamai_appsec_configuration.configuration.latest_version + name = var.name + description = var.description + contract_id = data.akamai_appsec_contracts_groups.contracts_groups.default_contractid + group_id = data.akamai_appsec_contracts_groups.contracts_groups.default_groupid + host_names = data.akamai_appsec_selectable_hostnames.selectable_hostnames.hostnames +} + +output "clone_config_id" { + value = akamai_appsec_configuration_clone.clone_config.config_id +} + +output "clone_config_version" { + value = akamai_appsec_configuration_clone.clone_config.version +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name to be applied to the new configuration. + +* `description` - (Required) A description of the new configuration. + +* `create_from_config_id` - (Required) The ID of the configuration to be cloned. + +* `create_from_version` - (Required) The version number of the configuration to be cloned. + +* `contract_id` - (Required) The contract id to use. + +* `group_id` - (Required) The group id to use. + +* `host_names` - (Required) The hostnames to be protected under the new configuration. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `config_id` - The ID of the newly created configuration. + +* `version` - The version number of the newly created configuration. + diff --git a/docs/resources/appsec_configuration_rename.md b/docs/resources/appsec_configuration_rename.md new file mode 100644 index 000000000..d7f862c99 --- /dev/null +++ b/docs/resources/appsec_configuration_rename.md @@ -0,0 +1,49 @@ +--- +layout: "akamai" +page_title: "Akamai: ConfigurationRename" +subcategory: "Application Security" +description: |- + ConfigurationRename +--- + +# akamai_appsec_configuration_rename + +The `akamai_appsec_configuration_rename` resource allows you to rename an existing security configuration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to rename an existing configuration +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +resource "akamai_appsec_configuration_rename" "configuration" { + config_id = data.akamai_appsec_configuration.configuration.config_id + name = var.name + description = var.description +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to be renamed. + +* `name` - (Required) The new name to be given to the configuration. + +* `description` - (Required) The description to be applied to the configuration. + +## Attribute Reference + +In addition to the arguments above, the following attributes are exported: + +* None + diff --git a/docs/resources/appsec_configuration_version_clone.md b/docs/resources/appsec_configuration_version_clone.md index 4d0149985..ddff0f99f 100644 --- a/docs/resources/appsec_configuration_version_clone.md +++ b/docs/resources/appsec_configuration_version_clone.md @@ -3,12 +3,11 @@ layout: "akamai" page_title: "Akamai: ConfigurationClone" subcategory: "Application Security" description: |- - ConfigurationClone + ConfigurationVersionClone --- # akamai_appsec_configuration_version_clone - The `akamai_appsec_configuration_version_clone` resource allows you to create a new version of a security configuration by cloning an existing version. ## Example Usage diff --git a/docs/resources/appsec_custom_deny.md b/docs/resources/appsec_custom_deny.md new file mode 100644 index 000000000..d2e2f2245 --- /dev/null +++ b/docs/resources/appsec_custom_deny.md @@ -0,0 +1,52 @@ +--- +layout: "akamai" +page_title: "Akamai: CustomDeny" +subcategory: "Application Security" +description: |- + CustomDeny +--- + +# resource_akamai_appsec_custom_deny + +The `resource_akamai_appsec_custom_deny` resource allows you to create a new custom deny action for a specific configuration version. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to create a custom deny action using a JSON definition +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} +resource "akamai_appsec_custom_deny" "custom_deny" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + custom_deny = file("${path.module}/custom_deny.json") +} + +output "custom_deny_id" { + value = akamai_appsec_custom_deny.custom_deny.custom_deny_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `custom_deny` - (Required) The JSON-formatted definition of the custom deny action ([format](https://developer.akamai.com/api/cloud_security/application_security/v1.html#63df3de3)). + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +*`custom_deny_id` - The ID of the new custom deny action. + diff --git a/docs/resources/appsec_custom_rule.md b/docs/resources/appsec_custom_rule.md index 360f2fe40..f961625cb 100644 --- a/docs/resources/appsec_custom_rule.md +++ b/docs/resources/appsec_custom_rule.md @@ -40,11 +40,12 @@ output "custom_rule_rule_id" { ## Argument Reference +The following arguments are supported: + * `config_id` - (Required) The ID of the security configuration to use. * `custom_rule` - (Required) The name of a JSON file containing a custom rule definition ([format](https://developer.akamai.com/api/cloud_security/application_security/v1.html#postcustomrules)). - ## Attribute Reference In addition to the arguments above, the following attribute is exported: diff --git a/docs/resources/appsec_custom_rule_action.md b/docs/resources/appsec_custom_rule_action.md index c0eb2b77d..afe708406 100644 --- a/docs/resources/appsec_custom_rule_action.md +++ b/docs/resources/appsec_custom_rule_action.md @@ -3,7 +3,7 @@ layout: "akamai" page_title: "Akamai: CustomRuleAction" subcategory: "Application Security" description: |- - CustomRuleAction + Custom Rule Action --- # akamai_appsec_custom_rule_action @@ -28,7 +28,7 @@ data "akamai_appsec_configuration" "configuration" { resource "akamai_appsec_custom_rule_action" "create_custom_rule_action" { config_id = data.akamai_appsec_configuration.configuration.config_id version = data.akamai_appsec_configuration.configuration.latest_version - policy_id = "crAP_75829" + security_policy_id = "crAP_75829" custom_rule_id = 12345 custom_rule_action = "alert" } @@ -47,15 +47,15 @@ The following arguments are supported: * `version` - (Required) The version number of the security configuration to use. -* `custom_rule_action` - (Required) The action to take when the custom rule is invoked: `alert` to record the trigger event, `deny` to block the request, `deny_custom_{custom_deny_id}` to execute a custom deny action, or `none` to take no action. +* `security_policy_id` - (Required) The security policy to use. -* `policy_id` - (Required) The +* `custom_rule_id` - (Required) The custom rule for which to apply the action. -* `custom_rule_id` - (Required) +* `custom_rule_action` - (Required) The action to take when the custom rule is invoked: `alert` to record the trigger event, `deny` to block the request, `deny_custom_{custom_deny_id}` to execute a custom deny action, or `none` to take no action. ## Attribute Reference In addition to the arguments above, the following attribute is exported: -* `custom_rule_id` - The ID of the custom rule. +* None diff --git a/docs/resources/appsec_eval_hostnames.md b/docs/resources/appsec_eval_hostnames.md new file mode 100644 index 000000000..e608cff45 --- /dev/null +++ b/docs/resources/appsec_eval_hostnames.md @@ -0,0 +1,49 @@ +--- +layout: "akamai" +page_title: "Akamai: EvalHostnames" +subcategory: "Application Security" +description: |- + EvalHostnames +--- + +# resource_akamai_appsec_eval_hostnames + +The `resource_akamai_appsec_eval_hostnames` resource allows you to update the list of hostnames you want to evaluate for a configuration version. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +// USE CASE: user wants to specify the hostnames to evaluate +resource "akamai_appsec_eval_hostnames" "eval_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + hostnames = var.hostnames +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `hostnames` - (Required) A list of evaluation hostnames to be used for the specified configuration version. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `output_text` - A tabular display of the updated evaluation hostname information. + diff --git a/docs/resources/appsec_eval_protect_host.md b/docs/resources/appsec_eval_protect_host.md new file mode 100644 index 000000000..f8d6190f0 --- /dev/null +++ b/docs/resources/appsec_eval_protect_host.md @@ -0,0 +1,54 @@ +--- +layout: "akamai" +page_title: "Akamai: EvalProtectHost" +subcategory: "Application Security" +description: |- + EvalProtectHost +--- + +# resource_akamai_appsec_eval_protect_host + +The `resource_akamai_appsec_eval_protect_host` resource allows you to move hostnames that you are evaluating to active protection. When you move a hostname from the evaluation hostnames list, it’s added to your security policy as a protected hostname. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to move the evaluation hosts to protected +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_eval_hostnames" "eval_hostnames" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +resource "akamai_appsec_eval_protect_host" "protect_host" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + hostnames = data.akamai_appsec_eval_hostnames.eval_hostnames.hostnames +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `hostnames` - (Required) The evaluation hostnames to be moved to active protection. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `output_text` - A tabular display of the updated evaluation hostname information. + diff --git a/docs/resources/appsec_ip_geo.md b/docs/resources/appsec_ip_geo.md index 167546ad4..9c4110509 100644 --- a/docs/resources/appsec_ip_geo.md +++ b/docs/resources/appsec_ip_geo.md @@ -93,4 +93,5 @@ The following arguments are supported: In addition to the arguments above, the following attributes are exported: -* `output_txt` - A tabular display of the IP/Geo firewall settings. +* `output_text` - A tabular display of the IP/Geo firewall settings. + diff --git a/docs/resources/appsec_penalty_box.md b/docs/resources/appsec_penalty_box.md index 8d2ce131c..388141d17 100644 --- a/docs/resources/appsec_penalty_box.md +++ b/docs/resources/appsec_penalty_box.md @@ -46,10 +46,9 @@ The following arguments are supported: * `penalty_box_action` - (Required) The action to take when penalty box protection is triggered: `alert` to record the trigger event, `deny` to block the request, `deny_custom_{custom_deny_id}` to execute a custom deny action, or `none` to take no action. Ignored if `penalty_box_protection` is set to `false`. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: -* `output_text` - A tabular display showing the updated penalty box protection settings. +* None diff --git a/docs/resources/appsec_reputation_profile_action.md b/docs/resources/appsec_reputation_profile_action.md index 617c40c83..e4aa1c3f0 100644 --- a/docs/resources/appsec_reputation_profile_action.md +++ b/docs/resources/appsec_reputation_profile_action.md @@ -54,7 +54,6 @@ The following arguments are supported: * `action` - (Required) The action to take when the specified reputation profile’s rule is triggered: `alert` to record the trigger event, `deny` to block the request, `deny_custom_{custom_deny_id}` to execute a custom deny action, or `none` to take no action. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/resources/appsec_reputation_profile_analysis.md b/docs/resources/appsec_reputation_profile_analysis.md new file mode 100644 index 000000000..a9d63d9a7 --- /dev/null +++ b/docs/resources/appsec_reputation_profile_analysis.md @@ -0,0 +1,55 @@ +--- +layout: "akamai" +page_title: "Akamai: ReputationProfileAnalysis" +subcategory: "Application Security" +description: |- + Reputation Profile Analysis +--- + +# resource_akamai_appsec_reputation_profile_analysis + +The `resource_akamai_appsec_reputation_profile_analysis` resource allows you to toggle the reputation analysis settings for a given security policy. The `forward_to_http_header` parameter indicates whether to add client reputation details to requests forwarded to origin in an HTTP header. The `forward_shared_ip_to_http_header_siem` parameter indicates whether to add value indicating that shared IPs are included in HTTP header and SIEM integration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +// USE CASE: user wants to set reputation analysis settings +resource "akamai_appsec_reputation_profile_analysis" "reputation_analysis" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + forward_to_http_header = true + forward_shared_ip_to_http_header_siem = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `security_policy_id` - (Required) The ID of the security_policy_id to which the settings should be applied. + +* `forward_to_http_header` - (Required) Whether to add client reputation details to requests forwarded to origin in an HTTP header. + +* `forward_shared_ip_to_http_header_siem` - (Required) Whether to add value indicating that shared IPs are included in HTTP header and SIEM integration. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* None + diff --git a/docs/resources/appsec_reputation_protection.md b/docs/resources/appsec_reputation_protection.md index 4d28e1a15..e45d575a3 100644 --- a/docs/resources/appsec_reputation_protection.md +++ b/docs/resources/appsec_reputation_protection.md @@ -44,7 +44,6 @@ The following arguments are supported: * `enabled` - (Required) Whether to enable reputation controls: either `true` or `false`. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/resources/appsec_security_policy.md b/docs/resources/appsec_security_policy.md new file mode 100644 index 000000000..48a463834 --- /dev/null +++ b/docs/resources/appsec_security_policy.md @@ -0,0 +1,59 @@ +--- +layout: "akamai" +page_title: "Akamai: SecurityPolicy" +subcategory: "Application Security" +description: |- + SecurityPolicy +--- + +# akamai_appsec_security_policy + +Use the `akamai_appsec_security_policy` resource to create a new security policy. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to create a new security policy +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +resource "akamai_appsec_security_policy" "security_policy_create" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + default_settings = var.default_settings + security_policy_name = var.policy_name + security_policy_prefix = var.policy_prefix +} + +output "security_policy_create" { + value = akamai_appsec_security_policy.security_policy_create.security_policy_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `security_policy_name` - (Required) The name of the new security policy. + +* `security_policy_prefix' - (Required) The four-character alphanumeric string prefix for the policy ID. + +* `default_settings` - (Optional) Whether the new policy should use the default settings. If not supplied, defaults to true. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `security_policy_id` - The ID of the newly created security policy. + diff --git a/docs/resources/appsec_security_policy_rename.md b/docs/resources/appsec_security_policy_rename.md new file mode 100644 index 000000000..12b7c6cdf --- /dev/null +++ b/docs/resources/appsec_security_policy_rename.md @@ -0,0 +1,51 @@ +--- +layout: "akamai" +page_title: "Akamai: SecurityPolicyRename" +subcategory: "Application Security" +description: |- + SecurityPolicyRename +--- + +# akamai_appsec_security_policy_rename + +The `akamai_appsec_security_policy_rename` resource allows you to rename an existing security policy. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to rename a security policy +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} +resource "akamai_appsec_security_policy" "security_policy_rename" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + security_policy_id = var.security_policy_id + security_policy_name = var.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The ID of the security configuration to use. + +* `version` - (Required) The version number of the security configuration to use. + +* `security_policy_id` - (Required) The ID of the security policy to be renamed. + +* `security_policy_name` - (Required) The new name to be given to the security policy. + +## Attribute Reference + +In addition to the arguments above, the following attributes are exported: + +* None + diff --git a/docs/resources/appsec_selected_hostname.md b/docs/resources/appsec_selected_hostnames.md similarity index 85% rename from docs/resources/appsec_selected_hostname.md rename to docs/resources/appsec_selected_hostnames.md index 4b09b1c60..413ae3800 100644 --- a/docs/resources/appsec_selected_hostname.md +++ b/docs/resources/appsec_selected_hostnames.md @@ -1,15 +1,15 @@ --- layout: "akamai" -page_title: "Akamai: SelectedHostname" +page_title: "Akamai: SelectedHostnames" subcategory: "Application Security" description: |- - SelectedHostname + SelectedHostnames --- -# akamai_appsec_selected_hostname +# akamai_appsec_selected_hostnames -The `akamai_appsec_selected_hostname` resource allows you to set the list of hostnames protected under a given security configuration version. +The `akamai_appsec_selected_hostnames` resource allows you to set the list of hostnames protected under a given security configuration version. ## Example Usage diff --git a/docs/resources/appsec_siem_settings.md b/docs/resources/appsec_siem_settings.md new file mode 100644 index 000000000..1eebc7c88 --- /dev/null +++ b/docs/resources/appsec_siem_settings.md @@ -0,0 +1,70 @@ +--- +layout: "akamai" +page_title: "Akamai: SIEMSettings" +subcategory: "Application Security" +description: |- + SIEMSettings +--- + +# akamai_appsec_siem_settings + +Use the `akamai_appsec_siem_settings` resource to mpdate the SIEM integration settings for a specific configuration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +// USE CASE: user wants to update the siem settings +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +data "akamai_appsec_siem_definitions" "siem_definition" { + siem_definition_name = var.siem_definition_name +} + +data "akamai_appsec_security_policy" "security_policies" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version +} + +resource "akamai_appsec_siem_settings" "siem" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + enable_siem = true + enable_for_all_policies = false + enable_botman_siem = true + siem_id = data.akamai_appsec_siem_definitions.siem_definition.id + security_policy_ids = data.akamai_appsec_security_policy.security_policies.policy_list +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `enable_siem` - (Required) Whether you enabled SIEM in a security configuration version. + +* `enable_for_all_policies` - (Required) Whether you enabled SIEM for all the security policies in the configuration version. + +* `enable_botman_siem` - (Required) Whether you enabled SIEM for the Bot Manager events. + +* `siem_id` - (Required) An integer that uniquely identifies the SIEM settings. + +* `security_policy_ids` - (Required) The list of security policy identifiers for which to enable the SIEM integration. + +## Attributes Reference + +In addition to the arguments above, the following attribute is exported: + +* `output_text` - A tabular display showing the updated SIEM integration settings. + diff --git a/docs/resources/appsec_slow_post.md b/docs/resources/appsec_slow_post.md index 02eeecb52..15d1adf77 100644 --- a/docs/resources/appsec_slow_post.md +++ b/docs/resources/appsec_slow_post.md @@ -52,7 +52,6 @@ The following arguments are supported: * `duration_threshold_timeout` - (Required) The time in seconds before the first eight kilobytes of the POST body must be received to avoid triggering the specified `action`. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/resources/appsec_slowpost_protection.md b/docs/resources/appsec_slowpost_protection.md index 4f9a637b7..8778bba84 100644 --- a/docs/resources/appsec_slowpost_protection.md +++ b/docs/resources/appsec_slowpost_protection.md @@ -44,7 +44,6 @@ The following arguments are supported: * `enabled` - (Required) Whether to enable slowpost controls: either `true` or `false`. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/resources/appsec_version_notes.md b/docs/resources/appsec_version_notes.md new file mode 100644 index 000000000..12e9f7c12 --- /dev/null +++ b/docs/resources/appsec_version_notes.md @@ -0,0 +1,52 @@ +--- +layout: "akamai" +page_title: "Akamai: VersionNotes" +subcategory: "Application Security" +description: |- + VersionNotes +--- + +# akamai_appsec_version_notes + +Use the `akamai_appsec_version_notes` resource to update the version notes for a configuration. + +## Example Usage + +Basic usage: + +```hcl +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_configuration" "configuration" { + name = var.security_configuration +} + +// USE CASE: user wants to update the version notes of the latest version +resource "akamai_appsec_version_notes" "version_notes" { + config_id = data.akamai_appsec_configuration.configuration.config_id + version = data.akamai_appsec_configuration.configuration.latest_version + version_notes = var.version_notes +} +output "version_notes" { + value = akamai_appsec_version_notes.version_notes.output_text +} +``` + +## Argument Reference + +The following arguments are supported: + +* `config_id` - (Required) The configuration ID to use. + +* `version` - (Required) The version number of the configuration to use. + +* `version_notes` - (Required) A string containing the version notes to be used. + +## Attributes Reference + +In addition to the arguments above, the following attributes are exported: + +* `output_text` - A tabular display showing the updated version notes. + diff --git a/docs/resources/appsec_waf_protection.md b/docs/resources/appsec_waf_protection.md index 29d8f1e34..571acfebe 100644 --- a/docs/resources/appsec_waf_protection.md +++ b/docs/resources/appsec_waf_protection.md @@ -44,7 +44,6 @@ The following arguments are supported: * `enabled` - (Required) Whether to enable WAF controls: either `true` or `false`. - ## Attributes Reference In addition to the arguments above, the following attributes are exported: diff --git a/docs/resources/dns_record.md b/docs/resources/dns_record.md index 8fad44162..dfed59ce0 100644 --- a/docs/resources/dns_record.md +++ b/docs/resources/dns_record.md @@ -1,22 +1,22 @@ --- layout: "akamai" -page_title: "Akamai: dns record" +page_title: "Akamai: DNS Record" subcategory: "DNS" description: |- - DNS Record + DNS record --- # akamai_dns_record +Use the `akamai_dns_record` resource to configure a DNS record that can integrate with your existing DNS infrastructure. -The `akamai_dns_record` provides the resource for configuring a dns record to integrate easily with your existing DNS infrastructure to provide a secure, high performance, highly available and scalable solution for DNS hosting. +## Example usage -## Example Usage +Here are examples of an A record and a CNAME record. -Basic usage: +### An A record example -```hcl -### A Record Example +``` resource "akamai_dns_record" "origin" { zone = "origin.org" name = "origin.example.org" @@ -25,8 +25,11 @@ resource "akamai_dns_record" "origin" { ttl = 30 target = ["192.0.2.42"] } +``` ### CNAME Record Example + +``` resource "akamai_dns_record" "www" { zone = "example.com" name = "www.example.com" @@ -37,234 +40,250 @@ resource "akamai_dns_record" "www" { } ``` -## Argument Reference +## Argument reference [argument-reference] -The following arguments are supported for all record types: +This resource supports these arguments for all record types: -* `name` - (Required) The name of the record. The name is an owner name, that is, the name of the node to which this resource record pertains. -* `zone` - (Required) Domain zone, encapsulating any nested subdomains. +* `name` - (Required) The DNS record name. This is the node this DNS record is associated with. Also known as an owner name. +* `zone` - (Required) The domain zone, including any nested subdomains. * `recordType` - (Required) The DNS record type. -* `active` - (Ignored, Boolean) Maintained for backward compatibility -* `ttl` - (Required,Boolean) The TTL is a 32-bit signed integer that specifies the time interval that the resource record may be cached before the source of the information should be consulted again. A value of zero means that the RR can only be used for the transaction in progress, and should not be cached. Zero values can also be used for extremely volatile data. +* `ttl` - (Required) The time to live (TTL) is a 32-bit signed integer for the time the resource record is cached.
A value of `0` means that the resource record is not cached. It's only used for the transaction in progress and may be useful for extremely volatile data. -## Required Fields Per Record Type +## Additional arguments by record type -In addition to the fields listed in the prior section, type specific fields define the data makeup of each Record's data. This section identfies required fields per type. +This section lists additional required and optional arguments for specific record types. -### A Record -The following field is required: +### A record -* target - One or more IPv4 addresses, for example, 1.2.3.4. +An A record requires this argument: -### AAAA Record +* `target` - One or more IPv4 addresses, for example, 192.0.2.0. -The following field is required: +### AAAA record -* target - One or more IPv6 addresses, for example, 2001:0db8::ff00:0042:8329. +An AAAA record requires this argument: -### AFSDB Record +* `target` - One or more IPv6 addresses, for example, 2001:0db8::ff00:0042:8329. -The following fields are required: +### AFSDB record + +An AFSDB record requires these arguments: -* target - The domain name of the host having a server for the cell named by the owner name of the resource record. -* subtype- An integer between 0 and 65535, indicating the type of service provided by the host. +* `target` - The domain name of the host having a server for the cell named by the owner name of the resource record. +* `subtype` - An integer between `0` and `65535` that indicates the type of service provided by the host. -### AKAMAICDN Record +### AKAMAICDN record -The following field is required: +An AKAMAICDN record requires this argument: -* target - DNS name representing selected Edge Hostname name+domain. +* `target` - A DNS name representing the selected edge hostname and domain. -### AKAMAITLC Record +### AKAMAITLC record -No additional fields are required. The following fields are Computed. +No additional arguments are needed for AKAMAITLC records. This resource returns these computed attributes for this record type: -* dns_name - valid DNS name. -* answer_type - answer type. +* `dns_name` - A valid DNS name. +* `answer_type` - The answer type. -### CAA Record +### CAA record -The following field are required: +A certificate authority authorization (CAA) record requires this argument: -* target - One or more CA Authorizations. Each authorization contains three attributes: flags, property tag and property value. +* `target` - One or more certificate authority authorizations. Each authorization contains three attributes: flags, property tag, and property value. Example: + ``` target = ["0 issue \"caa1.example.net\"", "0 issuewild \"ca2.example.org\"", "0 issue ca1.example.net"] ``` -### CERT Record +### CERT record -The following fields are required: +A CERT record requires these arguments: -* type_value - numeric certificate type value -* type_mnemonic - mnemonic certificate type value. -* keytag - value computed for the key embedded in the certificate -* algorithm - identifies the cryptographic algorithm used to create the signature. -* certificate - certificate data +* `type_value` - A numeric certificate type value. +* `type_mnemonic` - A mnemonic certificate type value. +* `keytag` - A value computed for the key embedded in the certificate. +* `algorithm` - The cryptographic algorithm used to create the signature. +* `certificate` - Certificate data. -Note: Type can be configured either a numeric OR menmonic value. If both set, type_mnemonic takes precedent. +> **Note:** When entering the certificate type, you can enter `type_value`, `type_mnemonic`, or both arguments. If you use both, `type_mnemonic` takes precedence. -### CNAME Record +### CNAME record -The following field is required: +A CNAME record requires this argument: -* target - A domain name that specifies the canonical or primary name for the owner. The owner name is an alias. +* `target `- A domain name that specifies the canonical or primary name for the owner. The owner name is an alias. -### DNSKEY Record +### DNSKEY record -The following fields are required: +A DNSKEY record requires these arguments: -* flags -* protocol - Must have the value 3. The DNSKEY resource record must be treated as invalid during signature verification if it contains a value other than 3. -* algorithm - The public key’s cryptographic algorithm and determine the format of the public key field. -* key - Base 64 encoded value representing the public key, the format of which depends on the algorithm being used. +* `flags` +* `protocol` - Set to `3`. If the value isn't `3`, the DNSKEY resource record is treated as invalid during signature verification. +* `algorithm` - The public key’s cryptographic algorithm. This algorithm determines the format of the public key field. +* `key` - A Base64 encoded value representing the public key. The format used depends on the `algorithm`. -### DS Record +### DS record -The following fields are required: +A DS record requires these arguments: + +* `keytag` - The key tag of the DNSKEY record that the DS record refers to, in network byte order. +* `algorithm` - The algorithm number of the DNSKEY resource record referred to by the DS record. +* `digest_type` - Identifies the algorithm used to construct the digest. +* `digest` - A base 16 encoded DS record includes a digest of the DNSKEY record it refers to. The digest is conifgured the canonical form of the DNSKEY record's fully qualified owner name with the DNSKEY RDATA, and then applying the digest algorithm. + +### HINFO record -* keytag - The key tag of the DNSKEY resource record referred to by the DS record, in network byte order. -* algorithm - The algorithm number of the DNSKEY resource record referred to by the DS record. -* digest_type - Identifies the algorithm used to construct the digest. -* digest - The base 16 encoded DS record refers to a DNSKEY RR by including a digest of that DNSKEY RR. The digest is calculated by concatenating the canonical form of the fully qualified owner name of the DNSKEY RR with the DNSKEY RDATA, and then applying the digest algorithm. +A HINFO record requires these arguments: -### HINFO Record +* `hardware` - The type of hardware the host uses. A machine name or CPU type may be up to 40 characters long and include uppercase letters, digits, hyphens, and slashes. The entry needs to start and to end with an uppercase letter. +* `software` - The type of software the host uses. A system name may be up to 40 characters long and include uppercase letters, digits, hyphens, and slashes. The entry needs to start with an uppercase letter and end with an uppercase letter or a digit. + +### HTTPS Record The following fields are required: -* hardware - Type of hardware the host uses. A machine name or CPU type may be up to 40 characters taken from the set of uppercase letters, digits, and the two punctuation characters hyphen and slash. It must start with a letter, and end with a letter. -* software - Type of software the host uses. A system name may be up to 40 characters taken from the set of uppercase letters, digits, and the two punctuation characters hyphen and slash. It must start with a letter, and end with a letter or digit. +* `svc_priority` - Service priority associated with endpoint. Value mist be between 0 and 65535. A piority of 0 enables alias mode. +* `svc_params` - Space separated list of endpoint parameters. Not allowed if service priority is 0. +* `target_name` - Domain name of the service endpoint. -### LOC Record +### LOC record -The following field is required: +A LOC record requires this argument: -* target - A geographical location associated with a domain name. +* `target` - A geographical location associated with a domain name. -### MX Record +### MX record -The following field is required: +An MX record supports these arguments: -* target - One or more domain names that specifies a host willing to act as a mail exchange for the owner name. +* `target` - (Required) One or more domain names that specify a host willing to act as a mail exchange for the owner name. +* `priority` - (Optional) The preference value given to this MX record in relation to all other MX records. When a mailer needs to send mail to a certain DNS domain, it first contacts a DNS server for that domain and retrieves all the MX records. It then contacts the mailer with the lowest preference value. This value is ignored if an embedded priority exists in the target. +* `priority_increment` - (Optional) An auto priority increment when multiple targets are provided with no embedded priority. -The following fields are optional depending on configuration type. See [DNS Getting Started Guide](../guides/get_started_dns_zone.md#working-with-mx-records) for more information. +See [Working with MX records](../guides/get_started_dns_zone#working-with-mx-records) in the [DNS Getting Started Guide](../guides/get_started_dns_zone) for more information. -* priority - The preference value given to the MX record among MX records. When a mailer needs to send mail to a certain DNS domain, it first contacts a DNS server for that domain and retrieves all the MX records. It then contacts the mailer with the lowest preference value. Ignored if embedded priority specified in target -* priority_increment - auto priority increment when multiple targets are provided with no embedded priority. +### NAPTR record -### NAPTR Record +An NAPTR record requires these arguments: -The following fields are required: +* `order` - A 16-bit unsigned integer specifying the order in which the NAPTR records need to be processed to ensure the correct ordering of rules. Low numbers are processed before high numbers. Once a NAPTR is found whose rule matches the target, the client shouldn't consider any NAPTRs with a higher value for order (except as noted below for the flagsnapter field). +* `preference` - A 16-bit unsigned integer that specifies the order in which NAPTR records with equal order values are processed. Low numbers are processed before high numbers. +* `flagsnaptr` - A character string containing flags that control how fields in the record are rewritten and interpreted. Flags are single alphanumeric characters. +* `service` - Specifies the services available down this rewrite path. +* `regexp` - A regular expression string containing a substitution expression. This substitution expression is applied to the original client string in order to construct the next domain name to lookup. +* `replacement` - Depending on the value of the `flags` attribute, the next NAME to query for NAPTR, SRV, or address records. Enter a fully qualified domain name as the value. -* order - A 16-bit unsigned integer specifying the order in which the NAPTR records MUST be processed to ensure the correct ordering ofrules. Low numbers are processed before high numbers, and once a NAPTR is found whose rule “matches” the target, the client MUST NOT consider any NAPTRs with a higher value for order (except as noted below for the Flags field). -* preference - A 16-bit unsigned integer that specifies the order in which NAPTR records with equal order values should be processed, low numbers being processed before high numbers. -* flagsnaptr - A containing flags to control aspects of the rewriting and interpretation of the fields in the record. Flags are single characters from the set [A-Z0-9]. The case of the alphabetic characters is not significant. -* service - Specifies the services available down this rewrite path. -* regexp - A String containing a substitution expression that is applied to the original string held by the client in order to construct the next domain name to lookup. -* replacement - The next NAME to query for NAPTR, SRV, or address records depending on the value of the flags field. This MUST be a fully qualified domain-name. +### NS record -### NS Record +An NS record requires these arguments: -The following field is required: +* `target` - One or more domain names that specify authoritative hosts for the specified class and domain. -* target - One or more domain names that specify authoritative hosts for the specified class and domain. +### NSEC3 record -### NSEC3 Record +An NSEC3 record requires these arguments: -The following fields are required: +* `algorithm` - The cryptographic hash algorithm used to construct the hash-value. +* `flags` - Eight one-bit flags you can use to indicate different processing. All undefined flags must be zero. +* `iterations` - The number of additional times the hash function has been performed. +* `salt` - The base 16 encoded salt value, which is appended to the original owner name before hashing. Used to defend against pre-calculated dictionary attacks. +* `next_hashed_owner_name` - Base 32 encoded. The next hashed owner name in hash order. This value is in binary format. Given the ordered set of all hashed owner names, the Next Hashed Owner Name field contains the hash of an owner name that immediately follows the owner name of the given NSEC3 RR. +* `type_bitmaps` - The resource record set types that exist at the original owner name of the NSEC3 RR. -* algorithm - The cryptographic hash algorithm used to construct the hash-value. -* flags - The 8 one-bit flags that can be used to indicate different processing. All undefined flags must be zero. -* iterations - The number of additional times the hash function has been performed. -* salt - The base 16 encoded salt value, which is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks. -* next_hashed_owner_name - Base 32 encoded. The next hashed owner name in hash order. This value is in binary format. Given the ordered set of all hashed owner names, the Next Hashed Owner Name field contains the hash of an owner name that immediately follows the owner name of the given NSEC3 RR. -* type_bitmaps - The resource record set types that exist at the original owner name of the NSEC3 RR. +### NSEC3PARAM record -### NSEC3PARAM Record +An NSEC3PARAM record requires these arguments: -The following fields are required: +* `algorithm` - The cryptographic hash algorithm used to construct the hash-value. +* `flags` - Eight one-bit flags that can be used to indicate different processing. All undefined flags must be zero. +* `iterations` - The number of additional times the hash function has been performed. +* `salt` - The base 16 encoded salt value, which is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks. -* algorithm - The cryptographic hash algorithm used to construct the hash-value. -* flags - The 8 one-bit flags that can be used to indicate different processing. All undefined flags must be zero. -* iterations - The number of additional times the hash function has been performed. -* salt - The base 16 encoded salt value, which is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks. +### PTR record -### PTR Record +A PTR record requires this argument: -The following field is required: +* `target` - A domain name that points to some location in the domain name space. -* target - A domain name that points to some location in the domain name space. +### RP record -### RP Record +An RP record requires these arguments: -The following fields are required: +* `mailbox` - A domain name that specifies the mailbox for the responsible person. +* `txt` - A domain name for which TXT resource records exist. -* mailbox - A domain name that specifies the mailbox for the responsible person. -* txt - A domain name for which TXT resource records exist. +### RRSIG record -### RRSIG Record +An RRSIG record requires these arguments: -The following fields are required: +* `type_covered` - The resource record set type covered by this signature. +* `algorithm` - Identifies the cryptographic algorithm used to create the signature. +* `original_ttl` - The TTL of the covered record set as it appears in the authoritative zone. +* `expiration` - The end point of this signature’s validity. The signature can`t be used for authentication past this point in time. +* `inception` - The start point of this signature’s validity. The signature can`t be used for authentication prior to this point in time. +* `keytag` - The Key Tag field contains the key tag value of the DNSKEY RR that validates this signature, in network byte order. +* `signer` - The owner of the DNSKEY resource record who validates this signature. +* `signature` - The base 64 encoded cryptographic signature that covers the RRSIG RDATA and covered record set. Format depends on the TSIG algorithm in use. +* `labels` - The Labels field specifies the number of labels in the original RRSIG RR owner name. The significance of this field is that a validator uses it to determine whether the answer was synthesized from a wildcard. If so, it can be used to determine what owner name was used in generating the signature. -* type_covered - The resource record set type covered by this signature. -* algorithm - The Algorithm Number field identifies the cryptographic algorithm used to create the signature. -* original_ttl - The TTL of the covered record set as it appears in the authoritative zone. -* expiration - The end point of this signature’s validity. The signature cannot be used for authentication past this point. -* inception - The start point of this signature’s validity. The signature cannot be used for authentication prior to this point. -* keytag - The Key Tag field contains the key tag value of the DNSKEY RR that validates this signature, in network byte order. -* signer - The owner of the DSNKEY resource record who validates this signature. -* signature - The base 64 encoded cryptographic signature that covers the RRSIG RDATA and covered record set. Format depends on the TSIG algorithm in use. -* labels - The Labels field specifies the number of labels in the original RRSIG RR owner name. The significance of this field is that a validator uses it to determine whether the answer was synthesized from a wildcard. If so, it can be used to determine what owner name was used in generating the signature. +### SPF record -### SPF Record +An SPF record requires this argument: -The following field is required: +* `target` - Indicates which hosts are, and are not, authorized to use a domain name for the “HELO” and “MAIL FROM” identities. -* target - Indicates which hosts are, and are not, authorized to use a domain name for the “HELO” and “MAIL FROM” identities. +### SRV record -### SRV Record +An SRV record requires these arguments: -The following fields are required: +* `target` - The domain name of the target host. +* `priority` - A 16-bit integer that specifies the preference given to this resource record among others at the same owner. Lower values are preferred. +* `weight` - A server selection mechanism that specifies a relative weight for entries with the same priority. Larger weights are given a proportionately higher probability of being selected. The range of this number is 0–65535, a 16-bit unsigned integer in network byte order. Domain administrators should use Weight 0 when there isn’t any server selection to do, to make the RR easier to read for humans. In the presence of records containing weights greater than 0, records with weight 0 should have a very small chance of being selected. +* `port` - The port on this target of this service. The range of this number is 0–65535, a 16-bit unsigned integer in network byte order. -* target - The domain name of the target host. -* priority - A 16-bit integer that specifies the preference given to this resource record among others at the same owner. Lower values are preferred. -* weight - A server selection mechanism, specifying a relative weight for entries with the same priority. Larger weights should be given a proportionately higher probability of being selected. The range of this number is 0–65535, a 16-bit unsigned integer in network byte order. Domain administrators should use Weight 0 when there isn’t any server selection to do, to make the RR easier to read for humans. In the presence of records containing weights greater than 0, records with weight 0 should have a very small chance of being selected. -* port - The port on this target of this service. The range of this number is 0–65535, a 16-bit unsigned integer in network byte order. +### SSHFP record -### SSHFP Record +An SSHFP record requires these arguments: -The following fields are required: +* `algorithm` - Describes the algorithm of the public key. The following values are assigned: `0` is reserved, `1` is for RSA, `2` is for DSS, and `3` is for ECDSA. +* `fingerprint_type` - Describes the message-digest algorithm used to calculate the fingerprint of the public key. The following values are assigned: 0 = reserved, 1 = SHA-1, 2 = SHA-256. +* `fingerprint` - The base 16 encoded fingerprint as calculated over the public key blob. The message-digest algorithm is presumed to produce an opaque octet string output, which is placed as-is in the RDATA fingerprint field. -* algorithm - Describes the algorithm of the public key. The following values are assigned: 0 = reserved; 1 = RSA; 2 = DSS, 3 = ECDSA -* fingerprint_type - Describes the message-digest algorithm used to calculate the fingerprint of the public key. The following values are assigned: 0 = reserved, 1 = SHA-1, 2 = SHA-256 -* fingerprint - The base 16 encoded fingerprint as calculated over the public key blob. The message-digest algorithm is presumed to produce an opaque octet string output, which is placed as-is in the RDATA fingerprint field. +### SOA record -### SOA Record +An SOA record requires these arguments: -The following fields are required: +* `name_server` - The domain name of the name server that was the original or primary source of data for this zone. +* `email_address` - A domain name that specifies the mailbox of this person responsible for this zone. +* `serial` - The unsigned version number between 0 and 214748364 of the original copy of the zone. +* `refresh` - A time interval between 0 and 214748364 before the zone should be refreshed. +* `retry` - A time interval between 0 and 214748364 that should elapse before a failed refresh should be retried. +* `expiry` - A time value between 0 and 214748364 that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative. +* `nxdomain_ttl` - The unsigned minimum TTL between 0 and 214748364 that should be exported with any resource record from this zone. -* name_server - The domain name of the name server that was the original or primary source of data for this zone. -* email_address - A domain name that specifies the mailbox of this person responsible for this zone. -* serial - The unsigned version number between 0 and 214748364 of the original copy of the zone. -* refresh - A time interval between 0 and 214748364 before the zone should be refreshed. -* retry - A time interval between 0 and 214748364 that should elapse before a failed refresh should be retried. -* expiry - A time value between 0 and 214748364 that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative. -* nxdomain_ttl - The unsigned minimum TTL between 0 and 214748364 that should be exported with any resource record from this zone. +### SVCB record -### TLSA Record +An SVCB record requires these arguments: -The following fields are required: +* `svc_priority` - Service priority associated with endpoint. Value mist be between 0 and 65535. A piority of 0 enables alias mode. +* `svc_params` - Space separated list of endpoint parameters. Not allowed if service priority is 0. +* `target_name` - Domain name of the service endpoint. + +### TLSA record + +A TLSA record requires these arguments: -* usage - specifies the provided association that will be used to match the certificate presented in the TLS handshake. -* selector - specifies which part of the TLS certificate presented by the server will be matched against the association data. -* match_type - specifies how the certificate association is presented. -* certificate - specifies the "certificate association data" to be matched. +* `usage` - Specifies the association used to match the certificate presented in the TLS handshake. +* `selector` - Specifies the part of the TLS certificate presented by the server that is matched against the association data. +* `match_type` - Specifies how the certificate association is presented. +* `certificate` - Specifies the certificate association data to be matched. -### TXT Record +### TXT record -The following field is required: +A TXT record requires this argument: -* target - One or more character strings. TXT RRs are used to hold descriptive text. The semantics of the text depends on the domain where it is found. +* `target` - One or more character strings. TXT resource records hold descriptive text. The semantics of the text depends on the domain where it is found. diff --git a/docs/resources/dns_zone.md b/docs/resources/dns_zone.md index 185916e6e..5bcda03dc 100644 --- a/docs/resources/dns_zone.md +++ b/docs/resources/dns_zone.md @@ -8,13 +8,13 @@ description: |- # akamai_dns_zone -The `akamai_dns_zone` provides the resource for configuring a DNS zone to integrate easily with your existing DNS infrastructure to provide a secure, high performance, highly available and scalable solution for DNS hosting. +Use the `akamai_dns_zone` resource to configure a DNS zone that integrates with your existing DNS infrastructure. -## Example Usage +## Example usage Basic usage: -```hcl +``` resource "akamai_dns_zone" "demozone" { contract = "ctr_1-AB123" group = 100 @@ -29,22 +29,21 @@ resource "akamai_dns_zone" "demozone" { } ``` -## Argument Reference - -The following arguments are supported: - -* `contract` - (Required) The contract ID. -* `group` - (Required) The currently selected group ID. -* `zone` - (Required) Domain zone, encapsulating any nested subdomains. -* `type` - (Required) Whether the zone is `primary` or `secondary`. -* `masters` - (Required for `secondary`) The names or addresses of the customer’s nameservers from which the zone data should be retrieved. -* `comment` - (Required) A descriptive comment. -* `sign_and_serve` - (Optional) Whether DNSSEC Sign&Serve is enabled. -* `sign_and_serve_algorithm` - (Optional) Algorithm used by Sign&Serve. -* `target` - (Required for Alias zones) The name of the zone whose configuration this zone will copy. -* `tsig_key` - (Optional) TSIG Key used in secure zone transfers - * `name` - key name - * `algorithm` - * `secret` -* `end_customer_id` - (Optional) - +## Argument reference + +This resource supports these arguments: + +* `comment` - (Required) A descriptive comment. +* `contract` - (Required) The contract ID. +* `group` - (Required) The currently selected group ID. +* `zone` - (Required) The domain zone, encapsulating any nested subdomains. +* `type` - (Required) Whether the zone is `primary`, `secondary`, or `alias`. +* `masters` - (Required for `secondary` zones) The names or IP addresses of the nameservers that the zone data should be retrieved from. +* `target` - (Required for `alias` zones) The name of the zone whose configuration this zone will copy. +* `sign_and_serve` - (Optional) Whether DNSSEC Sign and Serve is enabled. +* `sign_and_serve_algorithm` - (Optional) The algorithm used by Sign and Serve. +* `tsig_key` - (Optional) The TSIG Key used in secure zone transfers. If used, requires these arguments: + * `name` - The key name. + * `algorithm` - The hashing algorithm. + * `secret` - String known between transfer endpoints. +* `end_customer_id` - (Optional) A free form identifier for the zone. diff --git a/docs/resources/gtm_asmap.md b/docs/resources/gtm_asmap.md index 37f4e4ee6..907b518c5 100644 --- a/docs/resources/gtm_asmap.md +++ b/docs/resources/gtm_asmap.md @@ -8,13 +8,17 @@ description: |- # akamai_gtm_asmap -`akamai_gtm_asmap` provides the resource for creating, configuring and importing a gtm AS Map to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_map_name` +Use the `akamai_gtm_asmap` resource to create, configure, and import a GTM Autonomous System (AS) map. AS mapping lets you configure a GTM property that returns a CNAME based on the AS number associated with the requester's IP address. -## Example Usage +You can reuse maps for multiple properties or create new ones. AS maps split the Internet into multiple AS block zones. Properties that use AS maps can specify handout integers for each zone. AS mapping lets you configure a property that directs users to a specific environment or to the origin. + +~> **Note** Import requires an ID with this format: `existing_domain_name`:`existing_map_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_asmap" "demo_asmap" { domain = "demo_domain.akadns.net" name = "demo_as" @@ -23,29 +27,25 @@ resource "akamai_gtm_asmap" "demo_asmap" { nickname = "All Other AS numbers" } } -``` - -## Argument Reference -The following arguments are supported: +``` -Required +## Argument reference -* `domain` - Domain name -* `name` - Resource name -* `default_datacenter` - * `datacenter_id` - * `nickname` +This resource supports these arguments: -Optional - -* `wait_on_complete` - (Boolean, Default: `true`) Wait for transaction to complete -* `assignment` - (multiple allowed) - * `datacenter_id` - * `nickname` - * `as_numbers` - (List) +* `domain` - (Required) The GTM Domain name for the AS map. +* `name` - (Required) A descriptive label for the AS map. Properties set up for AS mapping can use this as reference. +* `default_datacenter` - (Required) A placeholder for all other AS zones not found in these AS zones. Requires these additional arguments: + * `datacenter_id` - (Required) A unique identifier for an existing data center in the domain. + * `nickname` - (Required) A descriptive label for all other AS zones, up to 128 characters. +* `wait_on_complete` - (Optional) A boolean that, if `true`, waits for transaction to complete. +* `assignment` - (Optional) Contains information about the AS zone groupings of AS IDs. You can have multiple entries with this argument. If used, requires these arguments: + * `datacenter_id` - A unique identifier for an existing data center in the domain. + * `nickname` - A descriptive label for the group. + * `as_numbers` - Specifies an array of AS numbers. -### Backing Schema Reference +## Schema reference -The GTM AS Map backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#asmap) +You can download the GTM AS Map backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#asmap) page. diff --git a/docs/resources/gtm_cidrmap.md b/docs/resources/gtm_cidrmap.md index 559e27a6d..00bda24fe 100644 --- a/docs/resources/gtm_cidrmap.md +++ b/docs/resources/gtm_cidrmap.md @@ -8,13 +8,17 @@ description: |- # akamai_gtm_cidrmap -`akamai_gtm_cidrmap` provides the resource for creating, configuring and importing a gtm Cidr Map to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_map_name` +Use the `akamai_gtm_cidrmap` resource to create, configure, and import a GTM Classless Inter-Domain Routing (CIDR) map. CIDR mapping uses the IP addresses of the requesting name server to provide IP-specific CNAME entries. CNAMEs let you direct internal users to a specific environment or direct them to the origin. This lets you provide different responses to an internal corporate DNS infrastructure, such as internal test environments and another answer for all other name servers (`default_datacenter`). -## Example Usage + CIDR maps split the Internet into multiple CIDR block zones. Properties that use a map can specify a handout CNAME for each zone on the property’s editing page. To configure a property for CIDR mapping, your domain needs at least one CIDR map defined. + +~> **Note** Import requires an ID with this format: `existing_domain_name`:`existing_map_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_cidrmap" "demo_cidrmap" { domain = "demo_domain.akadns.net" name = "demo_cidr" @@ -25,27 +29,22 @@ resource "akamai_gtm_cidrmap" "demo_cidrmap" { } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +This resource supports these arguments: -Required - -* `domain` - Domain name -* `name` - Resource name -* `default_datacenter` - * `datacenter_id` - * `nickname` - -Optional - -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `assignment` - (multiple allowed) - * `datacenter_id` - * `nickname` - * `blocks` - (List) +* `domain` - (Required) GTM Domain name for the AS Map. +* `name` - (Required) A descriptive label for the CIDR map, up to 255 characters. +* `default_datacenter` - (Required) A placeholder for all other CIDR zones not found in these CIDR zones. Requires these additional arguments: + * `datacenter_id` - (Required) For each property, an identifier for all other CIDR zones. + * `nickname` - (Required) A descriptive label for the all other CIDR blocks. +* `wait_on_complete` - (Optional) A boolean that, if set to `true`, waits for transaction to complete. +* `assignment` - (Optional) Contains information about the CIDR zone groupings of CIDR blocks. You can have multiple entries with this argument. If used, requires these additional arguments: + * `datacenter_id` - (Optional) A unique identifier for an existing data center in the domain. + * `nickname` - (Optional) A descriptive label for the CIDR zone group, up to 256 characters. + * `blocks` - (Optional, list) Specifies an array of CIDR blocks. -### Backing Schema Reference +## Schema reference -The GTM Cidr Map backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#cidrmap) +You can download the GTM CIDR Map backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#cidrmap) page. diff --git a/docs/resources/gtm_datacenter.md b/docs/resources/gtm_datacenter.md index b1efbb66c..035cdaa5a 100644 --- a/docs/resources/gtm_datacenter.md +++ b/docs/resources/gtm_datacenter.md @@ -8,59 +8,57 @@ description: |- # akamai_gtm_datacenter -`akamai_gtm_datacenter` provides the resource for creating, configuring and importing a gtm datacenter to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_datacenter_id` +Use the `akamai_gtm_datacenter` resource to create, configure, and import a GTM data center. A GTM data center represents a customer data center and is also known as a traffic target, a location containing many servers GTM can direct traffic to. -## Example Usage +GTM uses data centers to scale load balancing. For example, you might have data centers in both New York and Amsterdam and want to balance load between them. You can configure GTM to send US users to the New York data center and European users to the data center in Amsterdam. + +~> **Note** Import requires an ID with this format: `existing_domain_name`:`existing_datacenter_id`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_datacenter" "demo_datacenter" { domain = "demo_domain.akadns.net" nickname = "demo_datacenter" } ``` -## Argument Reference +## Argument reference -The following arguments are supported: +This resource supports these arguments: -Required +* `domain` - (Required) The GTM domain name for the data center. +* `wait_on_complete` - (Optional) A boolean, that if set to `true`, waits for transaction to complete. +* `nickname` - (Optional) A descriptive label for the data center. +* `default_load_object` - (Optional) Specifies the load reporting interface between you and the GTM system. If used, requires these additional arguments: + * `load_object` - A load object is a file that provides real-time information about the current load, maximum allowable load, and target load on each resource. + * `load_object_port` - Specifies the TCP port to connect to when requesting the load object. + * `load_servers` - Specifies a list of servers to request the load object from. +* `city` - (Optional) The name of the city where the data center is located. +* `clone_of` - (Optional) Identifies the data center’s `datacenter_id` of which this data center is a clone. +* `cloud_server_targeting` - (Optional) A boolean indicating whether to balance load between two or more servers in a cloud environment. +* `cloud_server_host_header_override` - (Optional) A boolean that, if set to `true`, Akamai's liveness test agents use the Host header configured in the liveness test. +* `continent` - (Optional) A two-letter code that specifies the continent where the data center maps to. +* `country` - (Optional) A two-letter ISO 3166 country code that specifies the country where the data center maps to. +* `latitude` - (Optional) Specifies the geographical latitude of the data center’s position. See also longitude within this object. +* `longitude` - (Optional) Specifies the geographic longitude of the data center’s position. See also latitude within this object. +* `state_or_province` - (Optional) Specifies a two-letter ISO 3166 country code for the state or province where the data center is located. -* `domain` - Domain name +## Attribute reference -Optional - -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `nickname` - datacenter nickname -* `default_load_object` - * `load_object` - * `load_object_port` - * `load_servers` - (List) -* `city` -* `clone_of` -* `cloud_server_targeting` - (Boolean) -* `cloud_server_host_header_override` - (Boolean) -* `continent` -* `country` -* `latitude` -* `longitude` -* `state_or_province` +This resource returns these computed attributes in the `terraform.tfstate` file: -Computed - -The following arguments will be found in terraform.tfstate and can be referenced throughout the configuration. The values can NOT be changed. - -* `datacenter_id` +* `datacenter_id` - A unique identifier for an existing data center in the domain. * `ping_interval` * `ping_packet_size` * `score_penalty` * `servermonitor_liveness_count` * `servermonitor_load_count` * `servermonitor_pool` -* `virtual` - (Boolean) - -### Backing Schema Reference +* `virtual` - A boolean indicating whether the data center is virtual or physical, the latter meaning the data center has an Akamai Network Agent installed, and its physical location (`latitude`, `longitude`) is fixed. Either `true` if virtual or `false` if physical. -The GTM Datacenter backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#datacenter) +## Schema reference +You can download the GTM Data Center backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#datacenter) page. diff --git a/docs/resources/gtm_domain.md b/docs/resources/gtm_domain.md index f2ab44356..82fcaa06a 100644 --- a/docs/resources/gtm_domain.md +++ b/docs/resources/gtm_domain.md @@ -8,13 +8,15 @@ description: |- # akamai_gtm_domain -`akamai_gtm_domain` provides the resource for creating, configuring and importing a gtm domain to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name` +Use the `akamai_gtm_domain` resource to create, configure, and import a GTM Domain, which is a basic building block of a traffic management configuration. -## Example Usage +~> **Note** Import requires an ID with this format: `existing_domain_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_domain" "demodomain" { contract = "XXX" group = 100 @@ -24,36 +26,31 @@ resource "akamai_gtm_domain" "demodomain" { } ``` -## Argument Reference - -The following arguments are supported: +## Argument reference -Required +This resource supports these arguments: -* `contract` - The contract ID (if creating domain) -* `group` - The currently selected group ID (if creating domain) -* `name` - Domain name -* `type` - Domain type +* `contract` - (Required) If creating a domain, the contract ID. +* `group` - (Required) If creating a domain, the currently selected group ID. +* `name` - (Required) The DNS name for a collection of GTM Properties. +* `type` - (Required) Th type of GTM domain. Options include `failover-only`, `static`, `weighted`, `basic`, or `full`. +* `wait_on_complete` - (Optional) A boolean that, if set to `true`, waits for transaction to complete. +* `comment` - (Optional) A descriptive note about changes to the domain. The maximum is 4000 characters. +* `email_notification_list` - (Optional) A list of email addresses to notify when a change is made to the domain. +* `default_timeout_penalty` - (Optional) Specifies the timeout penalty score. Default is `25`. +* `load_imbalance_percentage` - (Optional) Indicates the percentage of load imbalance factor (LIF) for the domain. +* `default_ssl_client_private_key` - (Optional) Specifies a Base64-encoded private key that corresponds with the TLS certificate for HTTPS, SMTPS, POPS, and TCPS liveness tests. +* `default_error_penalty` - (Optional) Specifies the download penalty score. The default is `75`. If the download encounters an error, the web agent computes a score that is either the download time in seconds or a penalty score. +* `cname_coalescing_enabled` - (Optional) A boolean that if set to `true`, GTM collapses CNAME redirections in DNS answers when it knows the target of the CNAME. +* `load_feedback` - (Optional) A boolean indicating whether one or more measurements of load (resources) are defined by you and supplied by each data center in real time to balance load. +* `default_ssl_client_certificate` - (Optional) Specifies an optional Base64-encoded certificate that corresponds with the private key for TLS-based liveness tests (HTTPS, SMTPS, POPS, and TCPS). +* `end_user_mapping_enabled` - (Optional) A boolean indicating whether whether the GTM Domain is using end user client subnet mapping. -Optional +## Attribute reference -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `comment` - A descriptive comment -* `email_notification_list` - (List) -* `default_timeout_penalty` - (Default: 25) -* `load_imbalance_percentage` -* `default_ssl_client_private_key` -* `default_error_penalty` - (Default: 75) -* `cname_coalescing_enabled` - (Boolean) -* `load_feedback` - (Boolean) -* `default_ssl_client_certificate` -* `end_user_mapping_enabled` - (Boolean) +This resource returns these computed attributes in the `terraform.tfstate` file: -Computed - -The following arguments will be found in terraform.tfstate and can be referenced throughout the configuration. The values can NOT be changed. - -* `default_unreachable_threshold` +* `default_unreachable_threshold` * `min_pingable_region_fraction` * `servermonitor_liveness_count` * `round_robin_prefix` @@ -74,7 +71,6 @@ The following arguments will be found in terraform.tfstate and can be referenced * `min_test_interval` * `ping_packet_size` -### Backing Schema Reference - -The GTM Domain backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#domain) +## Schema reference +You can download the GTM Domain backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#domain) page. diff --git a/docs/resources/gtm_geomap.md b/docs/resources/gtm_geomap.md index 001e1e6f0..c3a44fc96 100644 --- a/docs/resources/gtm_geomap.md +++ b/docs/resources/gtm_geomap.md @@ -8,13 +8,17 @@ description: |- # akamai_gtm_geomap -`akamai_gtm_geomap` provides the resource for creating, configuring and importing a gtm Geographic map to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_map_name` +Use the `akamai_gtm_geomap` resource to create, configure, and import a GTM Geographic map. Geographic mapping lets you configure a property that returns a CNAME based on the geographic location of the request. -## Example Usage +You can reuse maps for multiple properties or create new ones. To configure a property for geographic mapping, you need to define at least one geographic map for your domain. Each map needs at least two definitions. For example, you can have one definition that maps a set of countries to a specific data center, and a second definition that routes all other traffic. + +~> **Note** Import requires an ID with this format: `existing_domain_name`:`existing_map_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_geomap" "demo_geomap" { domain = "demo_domain.akadns.net" name = "demo_geo" @@ -25,27 +29,21 @@ resource "akamai_gtm_geomap" "demo_geomap" { } ``` -## Argument Reference - -The following arguments are supported: - -Required - -* `domain` - Domain name -* `name` - Resource name -* `default_datacenter` - * `datacenter_id` - * `nickname` +## Argument reference -Optional - -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `assignment` - (multiple allowed) - * `datacenter_id` - * `nickname` - * `countries` - (List) +This resource supports these arguments: -### Backing Schema Reference +* `domain` - (Required) GTM Domain name for the Geographic Map. +* `name` - (Required) A descriptive label for the Geographic map. +* `default_datacenter` - (Required) A placeholder for all other geographic zones. Requires these additional arguments: + * `datacenter_id` - (Required) For each property, an identifier for all other geographic zones. + * `nickname` - (Required) A descriptive label for all other geographic zones. +* `wait_on_complete` - (Optional) A boolean indicating whether to wait for transaction to complete. Set to `true` by default. +* `assignment` - (Optional) Contains information about the geographic zone groupings of countries. You can have multiple `assignment` arguments. If used, requires these additional arguments: + * `datacenter_id` - (Optional) A unique identifier for an existing data center in the domain. + * `nickname` - (Optional) A descriptive label for the group. + * `countries` - (Optional) Specifies an array of two-letter ISO 3166 country codes, or for finer subdivisions, the two-letter country code and the two-letter stateOrProvince code separated by a forward slash. -The GTM Geographic Map backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#geographicmap) +## Schema reference +You can download the GTM Geographic Map backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#geographicmap) page. diff --git a/docs/resources/gtm_property.md b/docs/resources/gtm_property.md index 0fad0b404..58be80837 100644 --- a/docs/resources/gtm_property.md +++ b/docs/resources/gtm_property.md @@ -8,13 +8,15 @@ description: |- # akamai_gtm_property -`akamai_gtm_property` provides the resource for creating, configuring and importing a gtm property to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_property_name` +Use the `akamai_gtm_property` resource provides the resource for creating, configuring and importing a GTM property, a set of IP addresses or CNAMEs that GTM provides in response to DNS queries based on a set of rules. -## Example Usage +~> **Note** Import requires an ID with this format: `existing_domain_name`:`existing_property_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_property" "demo_property" { domain = "demo_domain.akadns.net" name = "demo_property" @@ -28,90 +30,84 @@ resource "akamai_gtm_property" "demo_property" { } ``` -## Argument Reference - -The following arguments are supported: - -Required - -* `domain` - Domain name -* `name` - Property name -* `type` - Property type -* `score_aggregation_type` -* `handout_limit` -* `handout_mode` -* `traffic_target` - (multiple allowed) - * `datacenter_id` - * `enabled` - (Boolean) - * `weight` - * `servers` - (List) - * `name` - Traffic target name - * `handout_cname` - -Optional - -* `liveness_test` - (multiple allowed) - * `name` - Liveness test name - * `test_interval` - * `test_object_protocol` - * `test_timeout` - * `answers_required` - (Boolean) - * `disabled` - (Boolean) - * `disable_nonstandard_port_warning` - (Boolean) - * `error_penalty` - * `http_header` - (multiple allowed) - `name` - `value` - * `http_error3xx` - (Boolean) - * `http_error4xx` - (Boolean) - * `http_error5xx` - (Boolean) - * `peer_certificate_verification` - (Boolean) - * `recursion_requested` - (Boolean) - * `request_string` - * `resource_type` - * `response_string` - * `ssl_client_certificate` - * `ssl_client_private_key` - * `test_object` - * `test_object_password` - * `test_object_port` - * `test_object_username` - * `timeout_penalty` -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `failover_delay` -* `failback_delay` -* `ipv6` - (Boolean) -* `stickiness_bonus_percentage` -* `stickiness_bonus_constant` -* `health_threshold` -* `use_computed_targets` - (Boolean) -* `backup_ip` -* `balance_by_download_score` - (Boolean) -* `static_ttl` -* `unreachable_threshold` -* `health_multiplier` -* `dynamic_ttl` -* `max_unreachable_penalty` -* `map_name` -* `load_imbalance_percentage` -* `health_max` -* `cname` -* `comments` -* `ghost_demand_reporting` -* `min_live_fraction` -* `static_rr_set` - (multiple allowed) - * `type` - * `ttl` - * `rdata` - (List) - -Computed - -The following arguments will be found in terraform.tfstate and can be referenced throughout the configuration. The values can NOT be changed. +## Argument reference + +This resource supports these arguments: + +* `domain` - (Required) DNS name for the GTM Domain set that includes this Property. +* `name` - (Required) DNS name for a collection of IP address or CNAME responses. The value, together with the GTM domainName, forms the Property’s hostname. +* `type` - (Required) Specifies the load balancing behavior for the property. Either failover, geographic, cidrmapping, weighted-round-robin, weighted-hashed, weighted-round-robin-load-feedback, qtr, or performance. +* `score_aggregation_type` - (Required) Specifies how GTM aggregates liveness test scores across different tests, when multiple tests are configured. +* `handout_limit` - (Required) Indicates the limit for the number of live IPs handed out to a DNS request. +* `handout_mode` - (Required) Specifies how IPs are returned when more than one IP is alive and available. +* `traffic_target` - (Required) Contains information about where to direct data center traffic. You can have multiple `traffic_target` arguments. If used, requires these arguments: + * `datacenter_id` - (Required) A unique identifier for an existing data center in the domain. + * `enabled` - (Required) A boolean indicating whether the traffic target is used. You can also omit the traffic target, which has the same result as the false value. + * `weight` - (Required) Specifies the traffic weight for the target. + * `servers` - (Required) (List) Identifies the IP address or the hostnames of the servers. + * `name` - (Required) An alternative label for the traffic target. + * `handout_cname` - (Required) Specifies an optional data center for the property. Used when there are no servers configured for the property. +* `liveness_test` - (Optional) Contains information about the liveness tests, which are run periodically to determine whether your servers respond to requests. You can have multiple `liveness_test` arguments. If used, requires these arguments: + * `name` - (Optional) A descriptive name for the liveness test. + * `test_interval` - (Optional) Indicates the interval at which the liveness test is run, in seconds. Requires a minimum of 10 seconds. + * `test_object_protocol` - (Optional) Specifies the test protocol. Possible values include `DNS`, `HTTP`, `HTTPS`, `FTP`, `POP`, `POPS`, `SMTP`, `SMTPS`, `TCP`, or `TCPS`. + * `test_timeout` - (Optional) Specifies the duration of the liveness test before it fails. The range is from 0.001 to 60 seconds. + * `answers_required` - (Optional) If `test_object_protocol` is DNS, enter a boolean value if an answer is needed for the DNS query to be successful. + * `disabled` - (Optional) A boolean indicating whether the liveness test is disabled. When disabled, GTM stops running the test, effectively treating it as if it no longer exists. + * `disable_nonstandard_port_warning` - (Optional) A boolean that if set to `true`, disables warnings when non-standard ports are used. + * `error_penalty` - (Optional) Specifies the score that’s reported if the liveness test encounters an error other than timeout, such as connection refused, and 404. + * `http_header` - (Optional) Contains HTTP headers to send if the `test_object_protocol` is `http` or `https`. You can have multiple `http_header` entries. Requires these arguments: + * `name` - Name of HTTP header. + * `value` - Value of HTTP header. + * `http_error3xx` - (Optional) A boolean that if set to `true`, treats a 3xx HTTP response as a failure if the `test_object_protocol` is `http`, `https`, or `ftp`. + * `http_error4xx` - (Optional) A boolean that if set to `true`, treats a 4xx HTTP response as a failure if the `test_object_protocol` is `http`, `https`, or `ftp`. + * `http_error5xx` - (Optional) A boolean that if set to `true`, treats a 5xx HTTP response as a failure if the `test_object_protocol` is `http`, `https`, or `ftp`. + * `peer_certificate_verification` - (Optional) A boolean that if set to `true`, validates the origin certificate. Applies only to tests with `test_object_protocol` of https. + * `recursion_requested` - (Optional) A boolean indicating whether the `test_object_protocol` is DNS. The DNS query is recursive. + * `request_string` - (Optional) Specifies a request string. + * `resource_type` - (Optional) Specifies the query type, if `test_object_protocol` is DNS. + * `response_string` - (Optional) Specifies a response string. + * `ssl_client_certificate` - (Optional) Indicates a Base64-encoded certificate. SSL client certificates are available for livenessTests that use secure protocols. + * `ssl_client_private_key` - (Optional) Indicates a Base64-encoded private key. The private key used to generate or request a certificate for livenessTests can’t have a passphrase nor be used for any other purpose. + * `test_object` - (Optional) Specifies the static text that acts as a stand-in for the data that you’re sending on the network. + * `test_object_password` - (Optional) Specifies the test object’s password. It is required if testObjectProtocol is ftp. + * `test_object_port` - (Optional) Specifies the port number for the testObject. + * `test_object_username` - (Optional) A descriptive name for the testObject. + * `timeout_penalty`- (Optional) Specifies the score to be reported if the liveness test times out. +* `wait_on_complete` - (Optional) A boolean indicating whether to wait for transaction to complete. Set to `true` by default. +* `failover_delay` - (Optional) Specifies the failover delay in seconds. +* `failback_delay` - (Optional) Specifies the failback delay in seconds. +* `ipv6` - (Optional) A boolean that indicates the type of IP address handed out by a GTM property. +* `stickiness_bonus_percentage` - (Optional) Specifies a percentage used to configure data center affinity. +* `stickiness_bonus_constant` - (Optional) Specifies a constant used to configure data center affinity. +* `health_threshold` - (Optional) Configures a cutoff value that is computed from the median scores. +* `use_computed_targets` - (Optional) For load-feedback domains only, a boolean that indicates whether you want GTM to automatically compute target load. +* `backup_ip` - Specifies a backup IP. When GTM declares that all of the targets are down, the backupIP is handed out. +* `balance_by_download_score` - (Optional) A boolean that indicates whether download score based load balancing is enabled. +* `static_ttl` - (Optional) Specifies the TTL in seconds for static resource records that do not change based on the requesting name server IP. +* `unreachable_threshold` - (Optional) For performance domains, this specifies a penalty value that’s added to liveness test scores when data centers have an aggregated loss fraction higher than this value. +* `health_multiplier` - (Optional) Configures a cutoff value that is computed from the median scores. +* `dynamic_ttl` - (Optional) Indicates the TTL in seconds for records that might change dynamically based on liveness and load balancing such as A and AAAA records, and CNAMEs. +* `max_unreachable_penalty` - (Optional) For performance domains, this specifies a penalty value that’s added to liveness test scores when data centers show an aggregated loss fraction higher than the penalty value. +* `map_name` - (Optional) A descriptive label for a GeographicMap or a CidrMap that’s required if the property is either geographic or cidrmapping, in which case mapName needs to reference either an existing GeographicMap or CidrMap in the same domain. +* `load_imbalance_percentage` - (Optional) Indicates the percent of load imbalance factor (LIF) for the property. +* `health_max` - (Optional) Defines the absolute limit beyond which IPs are declared unhealthy. +* `cname` - (Optional) Indicates the fully qualified name aliased to a particular property. +* `comments` - (Optional) A descriptive note about changes to the domain. The maximum is 4000 characters. +* `ghost_demand_reporting` - (Optional) Use load estimates from Akamai Ghost utilization messages. +* `min_live_fraction` - (Optional) Specifies what fraction of the servers need to respond to requests so GTM considers the data center up and able to receive traffic. +* `static_rr_set` - (Optional) Contains static record sets. You can have multiple `static_rr_set` entries. Requires these arguments: + * `type` - (Optional) The record type. + * `ttl` - (Optional) The number of seconds that this record should live in a resolver’s cache before being refetched. + * `rdata` - (Optional) (List) An array of data strings, representing multiple records within a set. + +## Attribute reference + +This resource returns these computed attributes in the `terraform.tfstate` file: * `weighted_hash_bits_for_ipv4` * `weighted_hash_bits_for_ipv6` -### Backing Schema Reference - -The GTM Property backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#property) +## Schema reference +You can download the GTM Property backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#property) page. diff --git a/docs/resources/gtm_resource.md b/docs/resources/gtm_resource.md index 5a66d6d16..58ebebef5 100644 --- a/docs/resources/gtm_resource.md +++ b/docs/resources/gtm_resource.md @@ -8,13 +8,16 @@ description: |- # akamai_gtm_resource -`akamai_gtm_resource` provides the resource for creating, configuring and importing a gtm resource to integrate easily with your existing GTM infrastructure to provide a secure, high performance, highly available and scalable solution for Global Traffic Management. Note: Import requires an ID of the format: `existing_domain_name`:`existing_resource_name` +The `akamai_gtm_resource` lets you create, configure, and import a GTM resource. In GTM, a resource is anything you can measure whose scarcity affects load balancing. Examples of resources include bandwidth, CPU load average, database queries per second, or disk operations per second. -## Example Usage +~> **Note** Import requires an ID with this format: `existing_domain_name`: +`existing_resource_name`. + +## Example usage Basic usage: -```hcl +``` resource "akamai_gtm_resource" "demo_resource" { domain = "demo_domain.akadns.net" name = "demo_resource" @@ -23,37 +26,31 @@ resource "akamai_gtm_resource" "demo_resource" { } ``` -## Argument Reference - -The following arguments are supported: - -Required - -* `domain` - Domain name -* `name` - Resource name -* `aggregation_type` -* `type` - Resource type - -Optional - -* `wait_on_complete` - (Boolean, Default: true) Wait for transaction to complete -* `resource_instance` - (multiple allowed) - * `datacenter_id` - * `load_object` - * `load_object_port` - * `load_servers` - (List) - * `use_default_load_object` - (Boolean) -* `host_header` -* `least_squares_decay` -* `upper_bound` -* `description` -* `leader_string` -* `constrained_property` -* `load_imbalance_percent` -* `max_u_multiplicative_increment` -* `decay_rate` - -### Backing Schema Reference - -The GTM Resource backing schema and element descriptions can be found at [Akamai Developer Website](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#resource) - +## Argument reference + +This resource supports these arguments: + +* `domain` - (Required) DNS name for the GTM Domain set that includes this property. +* `name` - (Required) A descriptive label for the GTM resource. +* `aggregation_type` - (Required) Specifies how GTM handles different load numbers when multiple load servers are used for a data center or property. +* `type` - (Required) Indicates the kind of `load_object` format used to determine the load on the resource. +* `wait_on_complete` - (Optional) A boolean indicating whether to wait for transaction to complete. Set to `true` by default. +* `resource_instance` - (Optional) (multiple allowed) Contains information about the resources that constrain the properties within the data center. You can have multiple `resource_instance` entries. Requires these arguments: + * `datacenter_id` - (Optional) A unique identifier for an existing data center in the domain. + * `load_object` - (Optional) Identifies the load object file used to report real-time information about the current load, maximum allowable load, and target load on each resource. + * `load_object_port` - (Optional) Specifies the TCP port of the `load_object`. + * `load_servers` - (Optional) (List) Specifies a list of servers from which to request the load object. + * `use_default_load_object` - (Optional) A boolean that indicates whether a default `load_object` is used for the resources. +* `host_header` - (Optional) Optionally specifies the host header used when fetching the load object. +* `least_squares_decay` - (Optional) For internal use only. Unless Akamai indicates otherwise, omit the value or set it to null. +* `upper_bound` - (Optional) An optional sanity check that specifies the maximum allowed value for any component of the load object. +* `description` - (Optional) A descriptive note to help you track what the resource constrains. +* `leader_string` - (Optional) Specifies the text that comes before the `load_object`. +* `constrained_property` - (Optional) Specifies the name of the property that this resource constrains, enter `**` to constrain all properties. +* `load_imbalance_percent` - (Optional) Indicates the percent of load imbalance factor (LIF) for the property. +* `max_u_multiplicative_increment` - (Optional) For Akamai internal use only. You can omit the value or set it to `null`. +* `decay_rate` - (Optional) For Akamai internal use only. You can omit the value or set it to `null`. + +## Schema reference + +You can download the GTM Resource backing schema from the [Global Traffic Management API](https://developer.akamai.com/api/web_performance/global_traffic_management/v1.html#resource) page. diff --git a/go.mod b/go.mod index 41281da8a..ca21d9810 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/akamai/terraform-provider-akamai/v2 require ( - github.com/akamai/AkamaiOPEN-edgegrid-golang/v2 v2.1.1 + github.com/akamai/AkamaiOPEN-edgegrid-golang/v2 v2.2.0 github.com/allegro/bigcache v1.2.1 github.com/apex/log v1.9.0 github.com/aws/aws-sdk-go v1.31.9 // indirect diff --git a/pkg/akamai/log.go b/pkg/akamai/log.go index 8c7188f1b..33b9f5837 100644 --- a/pkg/akamai/log.go +++ b/pkg/akamai/log.go @@ -2,6 +2,7 @@ package akamai import ( "context" + "os" "strings" "github.com/apex/log" @@ -16,6 +17,19 @@ type ( } ) +// 2020/12/02 11:51:03 +const ( + DefaultTimestampFormat = "2006/01/02 03:04:05" +) + +func init() { + if fmt, ok := os.LookupEnv("AKAMAI_TS_FORMAT"); ok { + hclog.DefaultOptions.TimeFormat = fmt + } else { + hclog.DefaultOptions.TimeFormat = DefaultTimestampFormat + } +} + // LogFromHCLog returns a new log.Interface from an hclog.Logger func LogFromHCLog(l hclog.Logger) log.Interface { const ( diff --git a/pkg/providers/appsec/appsec_test.go b/pkg/providers/appsec/appsec_test.go index d4a0a6355..0de0ae360 100644 --- a/pkg/providers/appsec/appsec_test.go +++ b/pkg/providers/appsec/appsec_test.go @@ -31,6 +31,56 @@ func (p *mockappsec) GetConfigurationVersions(ctx context.Context, params appsec return args.Get(0).(*appsec.GetConfigurationVersionsResponse), args.Error(1) } +func (p *mockappsec) RemoveConfigurationVersionClone(ctx context.Context, params appsec.RemoveConfigurationVersionCloneRequest) (*appsec.RemoveConfigurationVersionCloneResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveConfigurationVersionCloneResponse), args.Error(1) +} + +func (p *mockappsec) GetConfigurationVersionClone(ctx context.Context, params appsec.GetConfigurationVersionCloneRequest) (*appsec.GetConfigurationVersionCloneResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetConfigurationVersionCloneResponse), args.Error(1) +} + +func (p *mockappsec) GetReputationAnalysis(ctx context.Context, params appsec.GetReputationAnalysisRequest) (*appsec.GetReputationAnalysisResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetReputationAnalysisResponse), args.Error(1) +} + +func (p *mockappsec) UpdateReputationAnalysis(ctx context.Context, params appsec.UpdateReputationAnalysisRequest) (*appsec.UpdateReputationAnalysisResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateReputationAnalysisResponse), args.Error(1) +} + +func (p *mockappsec) RemoveReputationAnalysis(ctx context.Context, params appsec.RemoveReputationAnalysisRequest) (*appsec.RemoveReputationAnalysisResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveReputationAnalysisResponse), args.Error(1) +} + func (p *mockappsec) CreateActivations(ctx context.Context, params appsec.CreateActivationsRequest, acknowledgeWarnings bool) (*appsec.CreateActivationsResponse, error) { args := p.Called(ctx, params) @@ -41,6 +91,16 @@ func (p *mockappsec) CreateActivations(ctx context.Context, params appsec.Create return args.Get(0).(*appsec.CreateActivationsResponse), args.Error(1) } +func (p *mockappsec) CreateConfigurationVersionClone(ctx context.Context, params appsec.CreateConfigurationVersionCloneRequest) (*appsec.CreateConfigurationVersionCloneResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.CreateConfigurationVersionCloneResponse), args.Error(1) +} + func (p *mockappsec) GetActivations(ctx context.Context, params appsec.GetActivationsRequest) (*appsec.GetActivationsResponse, error) { args := p.Called(ctx, params) @@ -61,6 +121,226 @@ func (p *mockappsec) RemoveActivations(ctx context.Context, params appsec.Remove return args.Get(0).(*appsec.RemoveActivationsResponse), args.Error(1) } +func (p *mockappsec) GetAdvancedSettingsLogging(ctx context.Context, params appsec.GetAdvancedSettingsLoggingRequest) (*appsec.GetAdvancedSettingsLoggingResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetAdvancedSettingsLoggingResponse), args.Error(1) +} + +func (p *mockappsec) RemoveAdvancedSettingsLogging(ctx context.Context, params appsec.RemoveAdvancedSettingsLoggingRequest) (*appsec.RemoveAdvancedSettingsLoggingResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveAdvancedSettingsLoggingResponse), args.Error(1) +} + +func (p *mockappsec) GetAdvancedSettingsPrefetch(ctx context.Context, params appsec.GetAdvancedSettingsPrefetchRequest) (*appsec.GetAdvancedSettingsPrefetchResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetAdvancedSettingsPrefetchResponse), args.Error(1) +} + +func (p *mockappsec) UpdateAdvancedSettingsPrefetch(ctx context.Context, params appsec.UpdateAdvancedSettingsPrefetchRequest) (*appsec.UpdateAdvancedSettingsPrefetchResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateAdvancedSettingsPrefetchResponse), args.Error(1) +} + +func (p *mockappsec) UpdateAdvancedSettingsLogging(ctx context.Context, params appsec.UpdateAdvancedSettingsLoggingRequest) (*appsec.UpdateAdvancedSettingsLoggingResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateAdvancedSettingsLoggingResponse), args.Error(1) +} + +func (p *mockappsec) GetApiEndpoints(ctx context.Context, params appsec.GetApiEndpointsRequest) (*appsec.GetApiEndpointsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetApiEndpointsResponse), args.Error(1) +} + +func (p *mockappsec) GetApiHostnameCoverage(ctx context.Context, params appsec.GetApiHostnameCoverageRequest) (*appsec.GetApiHostnameCoverageResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetApiHostnameCoverageResponse), args.Error(1) +} + +func (p *mockappsec) GetApiHostnameCoverageOverlapping(ctx context.Context, params appsec.GetApiHostnameCoverageOverlappingRequest) (*appsec.GetApiHostnameCoverageOverlappingResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetApiHostnameCoverageOverlappingResponse), args.Error(1) +} + +func (p *mockappsec) GetApiHostnameCoverageMatchTargets(ctx context.Context, params appsec.GetApiHostnameCoverageMatchTargetsRequest) (*appsec.GetApiHostnameCoverageMatchTargetsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetApiHostnameCoverageMatchTargetsResponse), args.Error(1) +} + +func (p *mockappsec) GetApiRequestConstraints(ctx context.Context, params appsec.GetApiRequestConstraintsRequest) (*appsec.GetApiRequestConstraintsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetApiRequestConstraintsResponse), args.Error(1) +} + +func (p *mockappsec) UpdateApiRequestConstraints(ctx context.Context, params appsec.UpdateApiRequestConstraintsRequest) (*appsec.UpdateApiRequestConstraintsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateApiRequestConstraintsResponse), args.Error(1) +} + +func (p *mockappsec) RemoveApiRequestConstraints(ctx context.Context, params appsec.RemoveApiRequestConstraintsRequest) (*appsec.RemoveApiRequestConstraintsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveApiRequestConstraintsResponse), args.Error(1) +} + +func (p *mockappsec) GetContractsGroups(ctx context.Context, params appsec.GetContractsGroupsRequest) (*appsec.GetContractsGroupsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetContractsGroupsResponse), args.Error(1) +} + +func (p *mockappsec) GetBypassNetworkLists(ctx context.Context, params appsec.GetBypassNetworkListsRequest) (*appsec.GetBypassNetworkListsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetBypassNetworkListsResponse), args.Error(1) +} + +func (p *mockappsec) UpdateBypassNetworkLists(ctx context.Context, params appsec.UpdateBypassNetworkListsRequest) (*appsec.UpdateBypassNetworkListsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateBypassNetworkListsResponse), args.Error(1) +} + +func (p *mockappsec) RemoveBypassNetworkLists(ctx context.Context, params appsec.RemoveBypassNetworkListsRequest) (*appsec.RemoveBypassNetworkListsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveBypassNetworkListsResponse), args.Error(1) +} + +func (p *mockappsec) GetVersionNotes(ctx context.Context, params appsec.GetVersionNotesRequest) (*appsec.GetVersionNotesResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetVersionNotesResponse), args.Error(1) +} + +func (p *mockappsec) UpdateVersionNotes(ctx context.Context, params appsec.UpdateVersionNotesRequest) (*appsec.UpdateVersionNotesResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateVersionNotesResponse), args.Error(1) +} + +func (p *mockappsec) CreateConfiguration(ctx context.Context, params appsec.CreateConfigurationRequest) (*appsec.CreateConfigurationResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.CreateConfigurationResponse), args.Error(1) +} + +func (p *mockappsec) RemoveConfiguration(ctx context.Context, params appsec.RemoveConfigurationRequest) (*appsec.RemoveConfigurationResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveConfigurationResponse), args.Error(1) +} + +func (p *mockappsec) UpdateConfiguration(ctx context.Context, params appsec.UpdateConfigurationRequest) (*appsec.UpdateConfigurationResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateConfigurationResponse), args.Error(1) +} + +func (p *mockappsec) GetConfiguration(ctx context.Context, params appsec.GetConfigurationRequest) (*appsec.GetConfigurationResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetConfigurationResponse), args.Error(1) +} + func (p *mockappsec) CreateConfigurationClone(ctx context.Context, params appsec.CreateConfigurationCloneRequest) (*appsec.CreateConfigurationCloneResponse, error) { args := p.Called(ctx, params) @@ -131,6 +411,66 @@ func (p *mockappsec) UpdateCustomRule(ctx context.Context, params appsec.UpdateC return args.Get(0).(*appsec.UpdateCustomRuleResponse), args.Error(1) } +func (p *mockappsec) CreateCustomDeny(ctx context.Context, params appsec.CreateCustomDenyRequest) (*appsec.CreateCustomDenyResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.CreateCustomDenyResponse), args.Error(1) +} + +func (p *mockappsec) GetCustomDeny(ctx context.Context, params appsec.GetCustomDenyRequest) (*appsec.GetCustomDenyResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetCustomDenyResponse), args.Error(1) +} + +func (p *mockappsec) GetCustomDenyList(ctx context.Context, params appsec.GetCustomDenyListRequest) (*appsec.GetCustomDenyListResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetCustomDenyListResponse), args.Error(1) +} + +func (p *mockappsec) RemoveCustomDeny(ctx context.Context, params appsec.RemoveCustomDenyRequest) (*appsec.RemoveCustomDenyResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveCustomDenyResponse), args.Error(1) +} + +func (p *mockappsec) UpdateCustomDeny(ctx context.Context, params appsec.UpdateCustomDenyRequest) (*appsec.UpdateCustomDenyResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateCustomDenyResponse), args.Error(1) +} + +func (p *mockappsec) GetFailoverHostnames(ctx context.Context, params appsec.GetFailoverHostnamesRequest) (*appsec.GetFailoverHostnamesResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetFailoverHostnamesResponse), args.Error(1) +} + func (p *mockappsec) CreateMatchTarget(ctx context.Context, params appsec.CreateMatchTargetRequest) (*appsec.CreateMatchTargetResponse, error) { args := p.Called(ctx, params) @@ -310,6 +650,46 @@ func (p *mockappsec) RemoveSecurityPolicy(ctx context.Context, params appsec.Rem return args.Get(0).(*appsec.RemoveSecurityPolicyResponse), args.Error(1) } +func (p *mockappsec) GetSiemDefinitions(ctx context.Context, params appsec.GetSiemDefinitionsRequest) (*appsec.GetSiemDefinitionsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetSiemDefinitionsResponse), args.Error(1) +} + +func (p *mockappsec) GetSiemSettings(ctx context.Context, params appsec.GetSiemSettingsRequest) (*appsec.GetSiemSettingsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetSiemSettingsResponse), args.Error(1) +} + +func (p *mockappsec) RemoveSiemSettings(ctx context.Context, params appsec.RemoveSiemSettingsRequest) (*appsec.RemoveSiemSettingsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveSiemSettingsResponse), args.Error(1) +} + +func (p *mockappsec) UpdateSiemSettings(ctx context.Context, params appsec.UpdateSiemSettingsRequest) (*appsec.UpdateSiemSettingsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateSiemSettingsResponse), args.Error(1) +} + func (p *mockappsec) GetCustomRule(ctx context.Context, params appsec.GetCustomRuleRequest) (*appsec.GetCustomRuleResponse, error) { args := p.Called(ctx, params) @@ -608,6 +988,76 @@ func (p *mockappsec) UpdateWAFMode(ctx context.Context, params appsec.UpdateWAFM return args.Get(0).(*appsec.UpdateWAFModeResponse), args.Error(1) } +func (p *mockappsec) GetEvalProtectHosts(ctx context.Context, params appsec.GetEvalProtectHostsRequest) (*appsec.GetEvalProtectHostsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetEvalProtectHostsResponse), args.Error(1) +} + +func (p *mockappsec) UpdateEvalProtectHost(ctx context.Context, params appsec.UpdateEvalProtectHostRequest) (*appsec.UpdateEvalProtectHostResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateEvalProtectHostResponse), args.Error(1) +} + +func (p *mockappsec) UpdateEvalHost(ctx context.Context, params appsec.UpdateEvalHostRequest) (*appsec.UpdateEvalHostResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.UpdateEvalHostResponse), args.Error(1) +} + +func (p *mockappsec) RemoveEvalHost(ctx context.Context, params appsec.RemoveEvalHostRequest) (*appsec.RemoveEvalHostResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.RemoveEvalHostResponse), args.Error(1) +} + +func (p *mockappsec) GetEvalProtectHost(ctx context.Context, params appsec.GetEvalProtectHostRequest) (*appsec.GetEvalProtectHostResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetEvalProtectHostResponse), args.Error(1) +} + +func (p *mockappsec) GetEvalHosts(ctx context.Context, params appsec.GetEvalHostsRequest) (*appsec.GetEvalHostsResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetEvalHostsResponse), args.Error(1) +} + +func (p *mockappsec) GetEvalHost(ctx context.Context, params appsec.GetEvalHostRequest) (*appsec.GetEvalHostResponse, error) { + args := p.Called(ctx, params) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*appsec.GetEvalHostResponse), args.Error(1) +} + func (p *mockappsec) GetEval(ctx context.Context, params appsec.GetEvalRequest) (*appsec.GetEvalResponse, error) { args := p.Called(ctx, params) diff --git a/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging.go b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging.go new file mode 100644 index 000000000..474681fbe --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging.go @@ -0,0 +1,104 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceAdvancedSettingsLogging() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceAdvancedSettingsLoggingRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceAdvancedSettingsLoggingRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceAdvancedSettingsLoggingRead") + + getAdvancedSettingsLogging := appsec.GetAdvancedSettingsLoggingRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.PolicyID = policyid + + if policyid != "" { + + } else { + + } + + advancedsettingslogging, err := client.GetAdvancedSettingsLogging(ctx, getAdvancedSettingsLogging) + if err != nil { + logger.Errorf("calling 'getAdvancedSettingsLogging': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "advancedSettingsLoggingDS", advancedsettingslogging) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(advancedsettingslogging) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getAdvancedSettingsLogging.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging_test.go b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging_test.go new file mode 100644 index 000000000..9e80728ed --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_logging_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiAdvancedSettingsLogging_data_basic(t *testing.T) { + t.Run("match by AdvancedSettingsLogging ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetAdvancedSettingsLoggingResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSAdvancedSettingsLogging/AdvancedSettingsLogging.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetAdvancedSettingsLogging", + mock.Anything, // ctx is irrelevant for this test + appsec.GetAdvancedSettingsLoggingRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSAdvancedSettingsLogging/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_advanced_settings_logging.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch.go b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch.go new file mode 100644 index 000000000..33d6a6b39 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch.go @@ -0,0 +1,88 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceAdvancedSettingsPrefetch() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceAdvancedSettingsPrefetchRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceAdvancedSettingsPrefetchRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceAdvancedSettingsPrefetchRead") + + getAdvancedSettingsPrefetch := appsec.GetAdvancedSettingsPrefetchRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsPrefetch.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsPrefetch.Version = version + + advancedsettingsprefetch, err := client.GetAdvancedSettingsPrefetch(ctx, getAdvancedSettingsPrefetch) + if err != nil { + logger.Errorf("calling 'getAdvancedSettingsPrefetch': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "advancedSettingsPrefetchDS", advancedsettingsprefetch) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(advancedsettingsprefetch) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getAdvancedSettingsPrefetch.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch_test.go b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch_test.go new file mode 100644 index 000000000..d8053d694 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_advanced_settings_prefetch_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiAdvancedSettingsPrefetch_data_basic(t *testing.T) { + t.Run("match by AdvancedSettingsPrefetch ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetAdvancedSettingsPrefetchResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetAdvancedSettingsPrefetch", + mock.Anything, // ctx is irrelevant for this test + appsec.GetAdvancedSettingsPrefetchRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSAdvancedSettingsPrefetch/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_advanced_settings_prefetch.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_endpoints.go b/pkg/providers/appsec/data_akamai_appsec_api_endpoints.go new file mode 100644 index 000000000..9ec437f50 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_endpoints.go @@ -0,0 +1,129 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceApiEndpoints() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApiEndpointsRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Optional: true, + }, + "api_name": { + Type: schema.TypeString, + Optional: true, + }, + "id_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + Description: "List of endpoint IDs", + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceApiEndpointsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceApiEndpointsRead") + + getApiEndpoints := appsec.GetApiEndpointsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiEndpoints.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiEndpoints.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiEndpoints.PolicyID = policyid + + apiName, err := tools.GetStringValue("api_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiEndpoints.Name = apiName + + apiendpoints, err := client.GetApiEndpoints(ctx, getApiEndpoints) + if err != nil { + logger.Errorf("calling 'getApiEndpoints': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "apiEndpointsDS", apiendpoints) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(apiendpoints) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + var idList []int + + for _, ids := range apiendpoints.APIEndpoints { + + idList = append(idList, ids.ID) + } + + d.Set("id_list", idList) + // TODO errors out trying to set + /*if err := d.Set("id_list", idList); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + }*/ + + if len(apiendpoints.APIEndpoints) > 0 { + d.SetId(strconv.Itoa(apiendpoints.APIEndpoints[0].ID)) + } + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_waf_protections_test.go b/pkg/providers/appsec/data_akamai_appsec_api_endpoints_test.go similarity index 52% rename from pkg/providers/appsec/data_akamai_appsec_waf_protections_test.go rename to pkg/providers/appsec/data_akamai_appsec_api_endpoints_test.go index 305b84ec1..a47d07073 100644 --- a/pkg/providers/appsec/data_akamai_appsec_waf_protections_test.go +++ b/pkg/providers/appsec/data_akamai_appsec_api_endpoints_test.go @@ -9,17 +9,17 @@ import ( "github.com/stretchr/testify/mock" ) -func TestAccAkamaiWAFProtections_data_basic(t *testing.T) { - t.Run("match by WAFProtections ID", func(t *testing.T) { +func TestAccAkamaiApiEndpoints_data_basic(t *testing.T) { + t.Run("match by ApiEndpoints ID", func(t *testing.T) { client := &mockappsec{} - cv := appsec.GetWAFProtectionsResponse{} - expectJS := compactJSON(loadFixtureBytes("testdata/TestDSWAFProtections/WAFProtections.json")) + cv := appsec.GetApiEndpointsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSApiEndpoints/ApiEndpoints.json")) json.Unmarshal([]byte(expectJS), &cv) - client.On("GetWAFProtections", + client.On("GetApiEndpoints", mock.Anything, // ctx is irrelevant for this test - appsec.GetWAFProtectionsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", ApplyApplicationLayerControls: false}, + appsec.GetApiEndpointsRequest{ConfigID: 43253, Version: 7}, ).Return(&cv, nil) useClient(client, func() { @@ -28,9 +28,9 @@ func TestAccAkamaiWAFProtections_data_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: loadFixtureString("testdata/TestDSWAFProtections/match_by_id.tf"), + Config: loadFixtureString("testdata/TestDSApiEndpoints/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.akamai_appsec_waf_protection.test", "id", "43253"), + resource.TestCheckResourceAttr("data.akamai_appsec_api_endpoints.test", "id", "619183"), ), }, }, diff --git a/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage.go new file mode 100644 index 000000000..56e023f75 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage.go @@ -0,0 +1,73 @@ +package appsec + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceApiHostnameCoverage() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApiHostnameCoverageRead, + Schema: map[string]*schema.Schema{ + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceApiHostnameCoverageRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceApiHostnameCoverageRead") + + getApiHostnameCoverage := appsec.GetApiHostnameCoverageRequest{} + + apihostnamecoverage, err := client.GetApiHostnameCoverage(ctx, getApiHostnameCoverage) + if err != nil { + logger.Errorf("calling 'getApiHostnameCoverage': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "apiHostnameCoverageDS", apihostnamecoverage) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(apihostnamecoverage) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if len(apihostnamecoverage.HostnameCoverage) > 0 { + for _, configval := range apihostnamecoverage.HostnameCoverage { + if configval.Configuration != nil && configval.Configuration.ID != 0 { + d.SetId(strconv.Itoa(configval.Configuration.ID)) + } + } + } + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets.go new file mode 100644 index 000000000..a134d69e9 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets.go @@ -0,0 +1,98 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceApiHostnameCoverageMatchTargets() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApiHostnameCoverageMatchTargetsRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "hostname": { + Type: schema.TypeString, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceApiHostnameCoverageMatchTargetsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceApiHostnameCoverageMatchTargetsRead") + + getApiHostnameCoverageMatchTargets := appsec.GetApiHostnameCoverageMatchTargetsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageMatchTargets.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageMatchTargets.Version = version + + hostname, err := tools.GetStringValue("hostname", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageMatchTargets.Hostname = hostname + + apihostnamecoveragematchtargets, err := client.GetApiHostnameCoverageMatchTargets(ctx, getApiHostnameCoverageMatchTargets) + if err != nil { + logger.Errorf("calling 'getApiHostnameCoverageMatchTargets': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "apiHostnameCoverageMatchTargetsDS", apihostnamecoveragematchtargets) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(apihostnamecoveragematchtargets) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getApiHostnameCoverageMatchTargets.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets_test.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets_test.go new file mode 100644 index 000000000..d5db4a6a1 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_match_targets_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiApiHostnameCoverageMatchTargets_data_basic(t *testing.T) { + t.Run("match by ApiHostnameCoverageMatchTargets ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetApiHostnameCoverageMatchTargetsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSApiHostnameCoverageMatchTargets/ApiHostnameCoverageMatchTargets.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetApiHostnameCoverageMatchTargets", + mock.Anything, // ctx is irrelevant for this test + appsec.GetApiHostnameCoverageMatchTargetsRequest{ConfigID: 43253, Version: 7, Hostname: "rinaldi.sandbox.akamaideveloper.com"}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSApiHostnameCoverageMatchTargets/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_hostname_coverage_match_targets.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping.go new file mode 100644 index 000000000..558c3c7a7 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping.go @@ -0,0 +1,98 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceApiHostnameCoverageOverlapping() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApiHostnameCoverageOverlappingRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "hostname": { + Type: schema.TypeString, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceApiHostnameCoverageOverlappingRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceApiHostnameCoverageOverlappingRead") + + getApiHostnameCoverageOverlapping := appsec.GetApiHostnameCoverageOverlappingRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageOverlapping.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageOverlapping.Version = version + + hostname, err := tools.GetStringValue("hostname", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiHostnameCoverageOverlapping.Hostname = hostname + + apihostnamecoverageoverlapping, err := client.GetApiHostnameCoverageOverlapping(ctx, getApiHostnameCoverageOverlapping) + if err != nil { + logger.Errorf("calling 'getApiHostnameCoverageOverlapping': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "apiHostnameCoverageoverLappingDS", apihostnamecoverageoverlapping) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(apihostnamecoverageoverlapping) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getApiHostnameCoverageOverlapping.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping_test.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping_test.go new file mode 100644 index 000000000..7d5833d3c --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_overlapping_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiApiHostnameCoverageOverlapping_data_basic(t *testing.T) { + t.Run("match by ApiHostnameCoverageOverlapping ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetApiHostnameCoverageOverlappingResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSApiHostnameCoverageOverlapping/ApiHostnameCoverageOverlapping.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetApiHostnameCoverageOverlapping", + mock.Anything, // ctx is irrelevant for this test + appsec.GetApiHostnameCoverageOverlappingRequest{ConfigID: 43253, Version: 7, Hostname: "example.com"}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSApiHostnameCoverageOverlapping/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_hostname_coverage_overlapping.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_slowpost_protections_test.go b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_test.go similarity index 52% rename from pkg/providers/appsec/data_akamai_appsec_slowpost_protections_test.go rename to pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_test.go index cdad43826..4e56c0f20 100644 --- a/pkg/providers/appsec/data_akamai_appsec_slowpost_protections_test.go +++ b/pkg/providers/appsec/data_akamai_appsec_api_hostname_coverage_test.go @@ -9,17 +9,17 @@ import ( "github.com/stretchr/testify/mock" ) -func TestAccAkamaiSlowPostProtections_data_basic(t *testing.T) { - t.Run("match by SlowPostProtections ID", func(t *testing.T) { +func TestAccAkamaiApiHostnameCoverage_data_basic(t *testing.T) { + t.Run("match by ApiHostnameCoverage ID", func(t *testing.T) { client := &mockappsec{} - cv := appsec.GetSlowPostProtectionsResponse{} - expectJS := compactJSON(loadFixtureBytes("testdata/TestDSSlowPostProtections/SlowPostProtections.json")) + cv := appsec.GetApiHostnameCoverageResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSApiHostnameCoverage/ApiHostnameCoverage.json")) json.Unmarshal([]byte(expectJS), &cv) - client.On("GetSlowPostProtections", + client.On("GetApiHostnameCoverage", mock.Anything, // ctx is irrelevant for this test - appsec.GetSlowPostProtectionsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230"}, + appsec.GetApiHostnameCoverageRequest{ConfigID: 0, Version: 0}, ).Return(&cv, nil) useClient(client, func() { @@ -28,9 +28,9 @@ func TestAccAkamaiSlowPostProtections_data_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: loadFixtureString("testdata/TestDSSlowPostProtections/match_by_id.tf"), + Config: loadFixtureString("testdata/TestDSApiHostnameCoverage/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.akamai_appsec_slowpost_protections.test", "id", "43253"), + resource.TestCheckResourceAttr("data.akamai_appsec_hostname_coverage.test", "id", "3644"), ), }, }, diff --git a/pkg/providers/appsec/data_akamai_appsec_api_request_constraints.go b/pkg/providers/appsec/data_akamai_appsec_api_request_constraints.go new file mode 100644 index 000000000..e6bb2e200 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_request_constraints.go @@ -0,0 +1,108 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + v2 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceApiRequestConstraints() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceApiRequestConstraintsRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Required: true, + }, + "api_id": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceApiRequestConstraintsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceApiRequestConstraintsRead") + + getApiRequestConstraints := v2.GetApiRequestConstraintsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.PolicyID = policyid + + apiID, err := tools.GetIntValue("api_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.ApiID = apiID + + apirequestconstraints, err := client.GetApiRequestConstraints(ctx, getApiRequestConstraints) + if err != nil { + logger.Errorf("calling 'getApiRequestConstraints': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "apiRequestConstraintsDS", apirequestconstraints) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(apirequestconstraints) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getApiRequestConstraints.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_api_request_constraints_test.go b/pkg/providers/appsec/data_akamai_appsec_api_request_constraints_test.go new file mode 100644 index 000000000..79f28fc2c --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_api_request_constraints_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiApiRequestConstraints_data_basic(t *testing.T) { + t.Run("match by ApiRequestConstraints ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetApiRequestConstraintsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSApiRequestConstraints/ApiRequestConstraints.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetApiRequestConstraints", + mock.Anything, // ctx is irrelevant for this test + appsec.GetApiRequestConstraintsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", ApiID: 1}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSApiRequestConstraints/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_api_request_constraints.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_attack_group_actions.go b/pkg/providers/appsec/data_akamai_appsec_attack_group_actions.go index 56e35a870..458348337 100644 --- a/pkg/providers/appsec/data_akamai_appsec_attack_group_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_attack_group_actions.go @@ -55,7 +55,7 @@ func dataSourceAttackGroupActions() *schema.Resource { func dataSourceAttackGroupActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceAttackGroupActionsRead") + logger := meta.Log("APPSEC", "dataSourceAttackGroupActionsRead") getAttackGroupActions := appsec.GetAttackGroupActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_attack_group_condition_exception.go b/pkg/providers/appsec/data_akamai_appsec_attack_group_condition_exception.go index e9d75e5c5..76a326bfb 100644 --- a/pkg/providers/appsec/data_akamai_appsec_attack_group_condition_exception.go +++ b/pkg/providers/appsec/data_akamai_appsec_attack_group_condition_exception.go @@ -50,7 +50,7 @@ func dataSourceAttackGroupConditionException() *schema.Resource { func dataSourceAttackGroupConditionExceptionRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceAttackGroupConditionExceptionsRead") + logger := meta.Log("APPSEC", "dataSourceAttackGroupConditionExceptionRead") getAttackGroupConditionException := appsec.GetAttackGroupConditionExceptionRequest{} @@ -87,7 +87,7 @@ func dataSourceAttackGroupConditionExceptionRead(ctx context.Context, d *schema. ots := OutputTemplates{} InitTemplates(ots) - outputtext, err := RenderTemplates(ots, "RuleConditionException", attackgroupconditionexception) + outputtext, err := RenderTemplates(ots, "AttackGroupConditionException", attackgroupconditionexception) if err == nil { if err := d.Set("output_text", outputtext); err != nil { diff --git a/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists.go b/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists.go new file mode 100644 index 000000000..a70a0f5ce --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists.go @@ -0,0 +1,103 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceBypassNetworkLists() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceBypassNetworkListsRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "bypass_network_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceBypassNetworkListsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceBypassNetworkListsRead") + + getBypassNetworkLists := appsec.GetBypassNetworkListsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getBypassNetworkLists.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getBypassNetworkLists.Version = version + + bypassnetworklists, err := client.GetBypassNetworkLists(ctx, getBypassNetworkLists) + if err != nil { + logger.Errorf("calling 'getBypassNetworkLists': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "bypassNetworkListsDS", bypassnetworklists) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(bypassnetworklists) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + nldata := make([]string, 0, len(bypassnetworklists.NetworkLists)) + + for _, hosts := range bypassnetworklists.NetworkLists { + nldata = append(nldata, hosts.ID) + } + + if err := d.Set("bypass_network_list", nldata); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getBypassNetworkLists.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists_test.go b/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists_test.go new file mode 100644 index 000000000..59b0d16fc --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_bypass_network_lists_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiBypassNetworkLists_data_basic(t *testing.T) { + t.Run("match by BypassNetworkLists ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetBypassNetworkListsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSBypassNetworkLists/BypassNetworkLists.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetBypassNetworkLists", + mock.Anything, // ctx is irrelevant for this test + appsec.GetBypassNetworkListsRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSBypassNetworkLists/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_bypass_network_lists.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_configuration_version.go b/pkg/providers/appsec/data_akamai_appsec_configuration_version.go index ade5eb6dc..ecf17d3e6 100644 --- a/pkg/providers/appsec/data_akamai_appsec_configuration_version.go +++ b/pkg/providers/appsec/data_akamai_appsec_configuration_version.go @@ -49,7 +49,7 @@ func dataSourceConfigurationVersion() *schema.Resource { func dataSourceConfigurationVersionRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceConfigurationVersionRead") + logger := meta.Log("APPSEC", "dataSourceConfigurationVersionRead") getConfigurationVersion := appsec.GetConfigurationVersionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_contracts_groups.go b/pkg/providers/appsec/data_akamai_appsec_contracts_groups.go new file mode 100644 index 000000000..ffb7a817a --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_contracts_groups.go @@ -0,0 +1,108 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + + v2 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceContractsGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceContractsGroupsRead, + Schema: map[string]*schema.Schema{ + "contractid": { + Type: schema.TypeString, + Optional: true, + }, + "groupid": { + Type: schema.TypeInt, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + "default_contractid": { + Type: schema.TypeString, + Computed: true, + }, + "default_groupid": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func dataSourceContractsGroupsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceContractsGroupsRead") + + getContractsGroups := v2.GetContractsGroupsRequest{} + + contract, err := tools.GetStringValue("contractid", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getContractsGroups.ContractID = contract + + group, err := tools.GetIntValue("groupid", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getContractsGroups.GroupID = group + + contractsgroups, err := client.GetContractsGroups(ctx, getContractsGroups) + if err != nil { + logger.Errorf("calling 'getContractsGroups': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "contractsgroupsDS", contractsgroups) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(contractsgroups) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + for _, configval := range contractsgroups.ContractGroups { + + if configval.ContractID == contract && configval.GroupID == group { + if err := d.Set("default_contractid", contract); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + if err := d.Set("default_groupid", group); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } + } + if len(contractsgroups.ContractGroups) > 0 { + d.SetId(contractsgroups.ContractGroups[0].ContractID) + } + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_rate_protections_test.go b/pkg/providers/appsec/data_akamai_appsec_contracts_groups_test.go similarity index 54% rename from pkg/providers/appsec/data_akamai_appsec_rate_protections_test.go rename to pkg/providers/appsec/data_akamai_appsec_contracts_groups_test.go index 44cb9acba..7c741b326 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rate_protections_test.go +++ b/pkg/providers/appsec/data_akamai_appsec_contracts_groups_test.go @@ -9,17 +9,17 @@ import ( "github.com/stretchr/testify/mock" ) -func TestAccAkamaiRateProtections_data_basic(t *testing.T) { - t.Run("match by RateProtections ID", func(t *testing.T) { +func TestAccAkamaiContractsGroups_data_basic(t *testing.T) { + t.Run("match by ContractsGroups ID", func(t *testing.T) { client := &mockappsec{} - cv := appsec.GetRateProtectionsResponse{} - expectJS := compactJSON(loadFixtureBytes("testdata/TestDSRateProtections/RateProtections.json")) + cv := appsec.GetContractsGroupsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSContractsGroups/ContractsGroups.json")) json.Unmarshal([]byte(expectJS), &cv) - client.On("GetRateProtections", + client.On("GetContractsGroups", mock.Anything, // ctx is irrelevant for this test - appsec.GetRateProtectionsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230"}, + appsec.GetContractsGroupsRequest{}, ).Return(&cv, nil) useClient(client, func() { @@ -28,9 +28,9 @@ func TestAccAkamaiRateProtections_data_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: loadFixtureString("testdata/TestDSRateProtections/match_by_id.tf"), + Config: loadFixtureString("testdata/TestDSContractsGroups/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.akamai_appsec_rate_protections.test", "id", "43253"), + resource.TestCheckResourceAttr("data.akamai_appsec_contracts_groups.test", "id", "C-1FRYVV3"), ), }, }, diff --git a/pkg/providers/appsec/data_akamai_appsec_custom_deny.go b/pkg/providers/appsec/data_akamai_appsec_custom_deny.go new file mode 100644 index 000000000..308be74df --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_custom_deny.go @@ -0,0 +1,101 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceCustomDeny() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceCustomDenyRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "custom_deny_id": { + Type: schema.TypeString, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceCustomDenyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceCustomDenyRead") + + getCustomDeny := appsec.GetCustomDenyListRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomDeny.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomDeny.Version = version + + customDenyID, err := tools.GetStringValue("custom_deny_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomDeny.ID = customDenyID + + customdeny, err := client.GetCustomDenyList(ctx, getCustomDeny) + if err != nil { + logger.Errorf("calling 'getCustomDeny': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "customDenyDS", customdeny) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(customdeny) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if len(customdeny.CustomDenyList) > 0 { + + //d.SetId(strconv.Itoa(getCustomDeny.ConfigID)) + d.SetId(string(customdeny.CustomDenyList[0].ID)) + } + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_custom_deny_test.go b/pkg/providers/appsec/data_akamai_appsec_custom_deny_test.go new file mode 100644 index 000000000..b828a12f0 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_custom_deny_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiCustomDeny_data_basic(t *testing.T) { + t.Run("match by CustomDeny ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetCustomDenyListResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSCustomDeny/CustomDenyList.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetCustomDenyList", + mock.Anything, // ctx is irrelevant for this test + appsec.GetCustomDenyListRequest{ConfigID: 43253, Version: 7, ID: "deny_custom_54994"}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSCustomDeny/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_custom_deny.test", "custom_deny_id", "deny_custom_54994"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_custom_rule_actions.go b/pkg/providers/appsec/data_akamai_appsec_custom_rule_actions.go index 2438d2eca..766f0f310 100644 --- a/pkg/providers/appsec/data_akamai_appsec_custom_rule_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_custom_rule_actions.go @@ -45,7 +45,7 @@ func dataSourceCustomRuleActions() *schema.Resource { func dataSourceCustomRuleActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceCustomRuleActionsRead") + logger := meta.Log("APPSEC", "dataSourceCustomRuleActionsRead") getCustomRuleActions := appsec.GetCustomRuleActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_custom_rules.go b/pkg/providers/appsec/data_akamai_appsec_custom_rules.go index 8c6cb2504..c1a5c3212 100644 --- a/pkg/providers/appsec/data_akamai_appsec_custom_rules.go +++ b/pkg/providers/appsec/data_akamai_appsec_custom_rules.go @@ -2,6 +2,7 @@ package appsec import ( "context" + "encoding/json" "errors" "fmt" "strconv" @@ -21,6 +22,14 @@ func dataSourceCustomRules() *schema.Resource { Type: schema.TypeInt, Required: true, }, + "custom_rule_id": { + Type: schema.TypeInt, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, "output_text": { Type: schema.TypeString, Computed: true, @@ -33,7 +42,7 @@ func dataSourceCustomRules() *schema.Resource { func dataSourceCustomRulesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceCustomRulesRead") + logger := meta.Log("APPSEC", "dataSourceCustomRulesRead") getCustomRules := appsec.GetCustomRulesRequest{} @@ -43,6 +52,12 @@ func dataSourceCustomRulesRead(ctx context.Context, d *schema.ResourceData, m in } getCustomRules.ConfigID = configid + customzruleid, err := tools.GetIntValue("custom_rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRules.ID = customzruleid + customrules, err := client.GetCustomRules(ctx, getCustomRules) if err != nil { logger.Errorf("calling 'getCustomRules': %s", err.Error()) @@ -59,6 +74,15 @@ func dataSourceCustomRulesRead(ctx context.Context, d *schema.ResourceData, m in } } + jsonBody, err := json.Marshal(customrules) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(strconv.Itoa(getCustomRules.ConfigID)) return nil diff --git a/pkg/providers/appsec/data_akamai_appsec_eval.go b/pkg/providers/appsec/data_akamai_appsec_eval.go index 327ead46c..87f666cab 100644 --- a/pkg/providers/appsec/data_akamai_appsec_eval.go +++ b/pkg/providers/appsec/data_akamai_appsec_eval.go @@ -41,7 +41,7 @@ func dataSourceEval() *schema.Resource { func dataSourceEvalRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceEvalRead") + logger := meta.Log("APPSEC", "dataSourceEvalRead") getEval := appsec.GetEvalRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_eval_hostnames.go b/pkg/providers/appsec/data_akamai_appsec_eval_hostnames.go new file mode 100644 index 000000000..8aaa549e4 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_eval_hostnames.go @@ -0,0 +1,103 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceEvalHostnames() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceEvalHostnamesRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "hostnames": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceEvalHostnamesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceEvalHostnamesRead") + + getEvalHostnames := appsec.GetEvalHostsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalHostnames.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalHostnames.Version = version + + evalhostnames, err := client.GetEvalHosts(ctx, getEvalHostnames) + if err != nil { + logger.Errorf("calling 'getEvalHostnames': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "evalHostnamesDS", evalhostnames) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(evalhostnames) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + newhdata := make([]string, 0, len(evalhostnames.Hostnames)) + + for _, hosts := range evalhostnames.Hostnames { + newhdata = append(newhdata, hosts) + } + + if err := d.Set("hostnames", newhdata); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getEvalHostnames.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_eval_hostnames_test.go b/pkg/providers/appsec/data_akamai_appsec_eval_hostnames_test.go new file mode 100644 index 000000000..f7e1276eb --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_eval_hostnames_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiEvalHostnames_data_basic(t *testing.T) { + t.Run("match by EvalHostnames ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetEvalHostsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSEvalHostnames/EvalHostnames.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetEvalHosts", + mock.Anything, // ctx is irrelevant for this test + appsec.GetEvalHostsRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSEvalHostnames/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_eval_hostnames.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_eval_rule_actions.go b/pkg/providers/appsec/data_akamai_appsec_eval_rule_actions.go index e0ff43fab..97df8ca2a 100644 --- a/pkg/providers/appsec/data_akamai_appsec_eval_rule_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_eval_rule_actions.go @@ -54,7 +54,7 @@ func dataSourceEvalRuleActions() *schema.Resource { func dataSourceEvalRuleActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceEvalRuleActionsRead") + logger := meta.Log("APPSEC", "dataSourceEvalRuleActionsRead") getEvalRuleActions := appsec.GetEvalRuleActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_eval_rule_condition_exception.go b/pkg/providers/appsec/data_akamai_appsec_eval_rule_condition_exception.go index 8e3c4308a..dfc1b6ed8 100644 --- a/pkg/providers/appsec/data_akamai_appsec_eval_rule_condition_exception.go +++ b/pkg/providers/appsec/data_akamai_appsec_eval_rule_condition_exception.go @@ -50,7 +50,7 @@ func dataSourceEvalRuleConditionException() *schema.Resource { func dataSourceEvalRuleConditionExceptionRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceEvalRuleConditionExceptionRead") + logger := meta.Log("APPSEC", "dataSourceEvalRuleConditionExceptionRead") getEvalRuleConditionException := appsec.GetEvalRuleConditionExceptionRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_export_configuration.go b/pkg/providers/appsec/data_akamai_appsec_export_configuration.go index d1aafc70c..d1bba9f13 100644 --- a/pkg/providers/appsec/data_akamai_appsec_export_configuration.go +++ b/pkg/providers/appsec/data_akamai_appsec_export_configuration.go @@ -49,7 +49,7 @@ func dataSourceExportConfiguration() *schema.Resource { func dataSourceExportConfigurationRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceExportConfigurationRead") + logger := meta.Log("APPSEC", "dataSourceExportConfigurationRead") getExportConfiguration := appsec.GetExportConfigurationsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_failover_hostnames.go b/pkg/providers/appsec/data_akamai_appsec_failover_hostnames.go new file mode 100644 index 000000000..70204cb4a --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_failover_hostnames.go @@ -0,0 +1,95 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceFailoverHostnames() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceFailoverHostnamesRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + + "hostnames": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of hostnames", + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceFailoverHostnamesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceFailoverHostnamesRead") + + getFailoverHostnames := appsec.GetFailoverHostnamesRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getFailoverHostnames.ConfigID = configid + + failoverhostnames, err := client.GetFailoverHostnames(ctx, getFailoverHostnames) + if err != nil { + logger.Errorf("calling 'getFailoverHostnames': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "failoverHostnamesDS", failoverhostnames) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(failoverhostnames) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + newhdata := make([]string, 0, len(failoverhostnames.HostnameList)) + + for _, hosts := range failoverhostnames.HostnameList { + newhdata = append(newhdata, hosts.Hostname) + } + + if err := d.Set("hostnames", newhdata); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getFailoverHostnames.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_failover_hostnames_test.go b/pkg/providers/appsec/data_akamai_appsec_failover_hostnames_test.go new file mode 100644 index 000000000..9c8fadb0a --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_failover_hostnames_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiFailoverHostnames_data_basic(t *testing.T) { + t.Run("match by FailoverHostnames ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetFailoverHostnamesResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSFailoverHostnames/FailoverHostnames.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetFailoverHostnames", + mock.Anything, // ctx is irrelevant for this test + appsec.GetFailoverHostnamesRequest{ConfigID: 43253}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSFailoverHostnames/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_failover_hostnames.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_ip_geo.go b/pkg/providers/appsec/data_akamai_appsec_ip_geo.go index 1921ccf31..a6deb24d7 100644 --- a/pkg/providers/appsec/data_akamai_appsec_ip_geo.go +++ b/pkg/providers/appsec/data_akamai_appsec_ip_geo.go @@ -61,7 +61,7 @@ func dataSourceIPGeo() *schema.Resource { func dataSourceIPGeoRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceIPGeoRead") + logger := meta.Log("APPSEC", "dataSourceIPGeoRead") getIPGeo := appsec.GetIPGeoRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_match_targets.go b/pkg/providers/appsec/data_akamai_appsec_match_targets.go index dc6de8016..59e290db4 100644 --- a/pkg/providers/appsec/data_akamai_appsec_match_targets.go +++ b/pkg/providers/appsec/data_akamai_appsec_match_targets.go @@ -41,7 +41,7 @@ func dataSourceMatchTargets() *schema.Resource { func dataSourceMatchTargetsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceMatchTargetsRead") + logger := meta.Log("APPSEC", "dataSourceMatchTargetsRead") getMatchTargets := appsec.GetMatchTargetsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_match_targets_test.go b/pkg/providers/appsec/data_akamai_appsec_match_targets_test.go index caa01eacb..c99d35577 100644 --- a/pkg/providers/appsec/data_akamai_appsec_match_targets_test.go +++ b/pkg/providers/appsec/data_akamai_appsec_match_targets_test.go @@ -19,12 +19,12 @@ func TestAccAkamaiMatchTargets_data_basic(t *testing.T) { client.On("GetMatchTargets", mock.Anything, // ctx is irrelevant for this test - appsec.GetMatchTargetsRequest{ConfigID: 43253, ConfigVersion: 15}, + appsec.GetMatchTargetsRequest{ConfigID: 43253, ConfigVersion: 7}, ).Return(&cv, nil) useClient(client, func() { resource.Test(t, resource.TestCase{ - IsUnitTest: true, + IsUnitTest: false, Providers: testAccProviders, Steps: []resource.TestStep{ { diff --git a/pkg/providers/appsec/data_akamai_appsec_penalty_box.go b/pkg/providers/appsec/data_akamai_appsec_penalty_box.go index a785881c9..49a177e1a 100644 --- a/pkg/providers/appsec/data_akamai_appsec_penalty_box.go +++ b/pkg/providers/appsec/data_akamai_appsec_penalty_box.go @@ -51,7 +51,7 @@ func dataSourcePenaltyBox() *schema.Resource { func dataSourcePenaltyBoxRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourcePenaltyBoxRead") + logger := meta.Log("APPSEC", "dataSourcePenaltyBoxRead") getPenaltyBox := appsec.GetPenaltyBoxRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_rate_policies.go b/pkg/providers/appsec/data_akamai_appsec_rate_policies.go index c3565ed42..f3254e878 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rate_policies.go +++ b/pkg/providers/appsec/data_akamai_appsec_rate_policies.go @@ -46,7 +46,7 @@ func dataSourceRatePolicies() *schema.Resource { func dataSourceRatePoliciesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceRatePoliciesRead") + logger := meta.Log("APPSEC", "dataSourceRatePoliciesRead") getRatePolicies := appsec.GetRatePoliciesRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_rate_policy_actions.go b/pkg/providers/appsec/data_akamai_appsec_rate_policy_actions.go index b53259f8c..ccff394fa 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rate_policy_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_rate_policy_actions.go @@ -45,7 +45,7 @@ func dataSourceRatePolicyActions() *schema.Resource { func dataSourceRatePolicyActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceRatePolicyActionsRead") + logger := meta.Log("APPSEC", "dataSourceRatePolicyActionsRead") getRatePolicyActions := appsec.GetRatePolicyActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_reputation_analysis.go b/pkg/providers/appsec/data_akamai_appsec_reputation_analysis.go new file mode 100644 index 000000000..59c60dd94 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_reputation_analysis.go @@ -0,0 +1,100 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceReputationAnalysis() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceReputationAnalysisRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceReputationAnalysisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceReputationAnalysisRead") + + getReputationAnalysis := appsec.GetReputationAnalysisRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.PolicyID = policyid + + reputationanalysis, err := client.GetReputationAnalysis(ctx, getReputationAnalysis) + if err != nil { + logger.Errorf("calling 'getReputationAnalysis': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "reputationAnalysisDS", reputationanalysis) + if err == nil { + if err := d.Set("output_text", outputtext); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } + + jsonBody, err := json.Marshal(reputationanalysis) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getReputationAnalysis.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_reputation_protections_test.go b/pkg/providers/appsec/data_akamai_appsec_reputation_analysis_test.go similarity index 59% rename from pkg/providers/appsec/data_akamai_appsec_reputation_protections_test.go rename to pkg/providers/appsec/data_akamai_appsec_reputation_analysis_test.go index 99b99dfa3..76911d45c 100644 --- a/pkg/providers/appsec/data_akamai_appsec_reputation_protections_test.go +++ b/pkg/providers/appsec/data_akamai_appsec_reputation_analysis_test.go @@ -9,28 +9,28 @@ import ( "github.com/stretchr/testify/mock" ) -func TestAccAkamaiReputationProtections_data_basic(t *testing.T) { - t.Run("match by ReputationProtections ID", func(t *testing.T) { +func TestAccAkamaiReputationAnalysis_data_basic(t *testing.T) { + t.Run("match by ReputationAnalysis ID", func(t *testing.T) { client := &mockappsec{} - cv := appsec.GetReputationProtectionsResponse{} - expectJS := compactJSON(loadFixtureBytes("testdata/TestDSReputationProtections/ReputationProtections.json")) + cv := appsec.GetReputationAnalysisResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSReputationAnalysis/ReputationAnalysis.json")) json.Unmarshal([]byte(expectJS), &cv) - client.On("GetReputationProtections", + client.On("GetReputationAnalysis", mock.Anything, // ctx is irrelevant for this test - appsec.GetReputationProtectionsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230"}, + appsec.GetReputationAnalysisRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230"}, ).Return(&cv, nil) useClient(client, func() { resource.Test(t, resource.TestCase{ - IsUnitTest: false, + IsUnitTest: true, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: loadFixtureString("testdata/TestDSReputationProtections/match_by_id.tf"), + Config: loadFixtureString("testdata/TestDSReputationAnalysis/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.akamai_appsec_reputation_protections.test", "id", "43253"), + resource.TestCheckResourceAttr("data.akamai_appsec_reputation_profile_analysis.test", "id", "43253"), ), }, }, diff --git a/pkg/providers/appsec/data_akamai_appsec_reputation_profile_actions.go b/pkg/providers/appsec/data_akamai_appsec_reputation_profile_actions.go index 9eba6ded3..b279644f8 100644 --- a/pkg/providers/appsec/data_akamai_appsec_reputation_profile_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_reputation_profile_actions.go @@ -54,7 +54,7 @@ func dataSourceReputationProfileActions() *schema.Resource { func dataSourceReputationProfileActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceReputationProfileActionsRead") + logger := meta.Log("APPSEC", "dataSourceReputationProfileActionsRead") getReputationProfileActions := appsec.GetReputationProfileActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_reputation_profiles.go b/pkg/providers/appsec/data_akamai_appsec_reputation_profiles.go index e1aeb3562..d733878c4 100644 --- a/pkg/providers/appsec/data_akamai_appsec_reputation_profiles.go +++ b/pkg/providers/appsec/data_akamai_appsec_reputation_profiles.go @@ -46,7 +46,7 @@ func dataSourceReputationProfiles() *schema.Resource { func dataSourceReputationProfilesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceReputationProfilesRead") + logger := meta.Log("APPSEC", "dataSourceReputationProfilesRead") getReputationProfiles := appsec.GetReputationProfilesRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_reputation_protections.go b/pkg/providers/appsec/data_akamai_appsec_reputation_protections.go index 7c663f81e..a4e396a02 100644 --- a/pkg/providers/appsec/data_akamai_appsec_reputation_protections.go +++ b/pkg/providers/appsec/data_akamai_appsec_reputation_protections.go @@ -45,7 +45,7 @@ func dataSourceReputationProtections() *schema.Resource { func dataSourceReputationProtectionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceReputationProtectionsRead") + logger := meta.Log("APPSEC", "dataSourceReputationProtectionsRead") getReputationProtections := appsec.GetReputationProtectionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_rule_actions.go b/pkg/providers/appsec/data_akamai_appsec_rule_actions.go index 9967d2487..d3d4b6987 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rule_actions.go +++ b/pkg/providers/appsec/data_akamai_appsec_rule_actions.go @@ -54,7 +54,7 @@ func dataSourceRuleActions() *schema.Resource { func dataSourceRuleActionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceRuleActionsRead") + logger := meta.Log("APPSEC", "dataSourceRuleActionsRead") getRuleActions := appsec.GetRuleActionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_rule_condition_exception.go b/pkg/providers/appsec/data_akamai_appsec_rule_condition_exception.go index df6ebef1c..960f64920 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rule_condition_exception.go +++ b/pkg/providers/appsec/data_akamai_appsec_rule_condition_exception.go @@ -50,7 +50,7 @@ func dataSourceRuleConditionException() *schema.Resource { func dataSourceRuleConditionExceptionRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceRuleConditionExceptionRead") + logger := meta.Log("APPSEC", "dataSourceRuleConditionExceptionRead") getRuleConditionException := appsec.GetRuleConditionExceptionRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_rule_upgrade.go b/pkg/providers/appsec/data_akamai_appsec_rule_upgrade.go index d4754aa00..654d8e778 100644 --- a/pkg/providers/appsec/data_akamai_appsec_rule_upgrade.go +++ b/pkg/providers/appsec/data_akamai_appsec_rule_upgrade.go @@ -46,7 +46,7 @@ func dataSourceRuleUpgrade() *schema.Resource { func dataSourceRuleUpgradeRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceRuleUpgradeRead") + logger := meta.Log("APPSEC", "dataSourceRuleUpgradeRead") getRuleUpgrade := appsec.GetRuleUpgradeRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_security_policy.go b/pkg/providers/appsec/data_akamai_appsec_security_policy.go index 0b0d478ba..ce56ce6f2 100644 --- a/pkg/providers/appsec/data_akamai_appsec_security_policy.go +++ b/pkg/providers/appsec/data_akamai_appsec_security_policy.go @@ -51,7 +51,7 @@ func dataSourceSecurityPolicy() *schema.Resource { func dataSourceSecurityPolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSecurityPolicyRead") + logger := meta.Log("APPSEC", "dataSourceSecurityPolicyRead") getSecurityPolicy := appsec.GetSecurityPoliciesRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_security_policy_protections.go b/pkg/providers/appsec/data_akamai_appsec_security_policy_protections.go index ba44c8b20..c79a86737 100644 --- a/pkg/providers/appsec/data_akamai_appsec_security_policy_protections.go +++ b/pkg/providers/appsec/data_akamai_appsec_security_policy_protections.go @@ -74,7 +74,7 @@ func dataSourcePolicyProtections() *schema.Resource { func dataSourcePolicyProtectionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourcePolicyProtectionsRead") + logger := meta.Log("APPSEC", "dataSourcePolicyProtectionsRead") getPolicyProtections := appsec.GetPolicyProtectionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_selectable_hostnames.go b/pkg/providers/appsec/data_akamai_appsec_selectable_hostnames.go index 12dc4824b..a1fc95028 100644 --- a/pkg/providers/appsec/data_akamai_appsec_selectable_hostnames.go +++ b/pkg/providers/appsec/data_akamai_appsec_selectable_hostnames.go @@ -3,6 +3,7 @@ package appsec import ( "context" "encoding/json" + "errors" "fmt" "strconv" @@ -18,12 +19,24 @@ func dataSourceSelectableHostnames() *schema.Resource { ReadContext: dataSourceSelectableHostnamesRead, Schema: map[string]*schema.Schema{ "config_id": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"contractid", "groupid"}, }, "version": { - Type: schema.TypeInt, - Required: true, + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"contractid", "groupid"}, + }, + "contractid": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"config_id", "version"}, + }, + "groupid": { + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"config_id", "version"}, }, "active_in_staging": { Type: schema.TypeBool, @@ -56,12 +69,33 @@ func dataSourceSelectableHostnames() *schema.Resource { func dataSourceSelectableHostnamesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSelectableHostnamesRead") + logger := meta.Log("APPSEC", "dataSourceSelectableHostnamesRead") getSelectableHostnames := appsec.GetSelectableHostnamesRequest{} - getSelectableHostnames.ConfigID = d.Get("config_id").(int) - getSelectableHostnames.Version = d.Get("version").(int) + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSelectableHostnames.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSelectableHostnames.Version = version + + contract, err := tools.GetStringValue("contractid", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSelectableHostnames.ContractID = contract + + group, err := tools.GetIntValue("groupid", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSelectableHostnames.GroupID = group selectablehostnames, err := client.GetSelectableHostnames(ctx, getSelectableHostnames) if err != nil { diff --git a/pkg/providers/appsec/data_akamai_appsec_selected_hostnames.go b/pkg/providers/appsec/data_akamai_appsec_selected_hostnames.go index cbf96dd19..a426d5c11 100644 --- a/pkg/providers/appsec/data_akamai_appsec_selected_hostnames.go +++ b/pkg/providers/appsec/data_akamai_appsec_selected_hostnames.go @@ -50,7 +50,7 @@ func dataSourceSelectedHostnames() *schema.Resource { func dataSourceSelectedHostnamesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSelectedHostnamesRead") + logger := meta.Log("APPSEC", "dataSourceSelectedHostnamesRead") getSelectedHostnames := appsec.GetSelectedHostnamesRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_siem_definitions.go b/pkg/providers/appsec/data_akamai_appsec_siem_definitions.go new file mode 100644 index 000000000..12d52ed86 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_siem_definitions.go @@ -0,0 +1,80 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceSiemDefinitions() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceSiemDefinitionsRead, + Schema: map[string]*schema.Schema{ + "siem_definition_name": { + Type: schema.TypeString, + Optional: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + Description: "JSON Siem Definition", + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceSiemDefinitionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceSiemDefinitionsRead") + + getSiemDefinitions := appsec.GetSiemDefinitionsRequest{} + + siemDdefinitionName, err := tools.GetStringValue("siem_definition_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSiemDefinitions.SiemDefinitionName = siemDdefinitionName + + siemdefinitions, err := client.GetSiemDefinitions(ctx, getSiemDefinitions) + if err != nil { + logger.Errorf("calling 'getSiemDefinitions': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "siemDefinitionsDS", siemdefinitions) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(siemdefinitions) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if len(siemdefinitions.SiemDefinitions) > 0 { + d.SetId(strconv.Itoa(siemdefinitions.SiemDefinitions[0].ID)) + } + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_siem_definitions_test.go b/pkg/providers/appsec/data_akamai_appsec_siem_definitions_test.go new file mode 100644 index 000000000..4c53953a1 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_siem_definitions_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiSiemDefinitions_data_basic(t *testing.T) { + t.Run("match by SiemDefinitions ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetSiemDefinitionsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSSiemDefinitions/SiemDefinitions.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetSiemDefinitions", + mock.Anything, // ctx is irrelevant for this test + appsec.GetSiemDefinitionsRequest{ID: 0, SiemDefinitionName: "SIEM Version 01"}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSSiemDefinitions/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_siem_definitions.test", "id", "1"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_siem_settings.go b/pkg/providers/appsec/data_akamai_appsec_siem_settings.go new file mode 100644 index 000000000..ce3572425 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_siem_settings.go @@ -0,0 +1,86 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + v2 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceSiemSettings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceSiemSettingsRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceSiemSettingsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceSiemSettingsRead") + + getSiemSettings := v2.GetSiemSettingsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSiemSettings.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSiemSettings.Version = version + + siemsettings, err := client.GetSiemSettings(ctx, getSiemSettings) + if err != nil { + logger.Errorf("calling 'getSiemSettings': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "siemsettingsDS", siemsettings) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(siemsettings) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(strconv.Itoa(getSiemSettings.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_siem_settings_test.go b/pkg/providers/appsec/data_akamai_appsec_siem_settings_test.go new file mode 100644 index 000000000..e4d307a41 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_siem_settings_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiSiemSettings_data_basic(t *testing.T) { + t.Run("match by SiemSettings ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetSiemSettingsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSSiemSettings/SiemSettings.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetSiemSettings", + mock.Anything, // ctx is irrelevant for this test + appsec.GetSiemSettingsRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSSiemSettings/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_siem_settings.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_slow_post_protection_settings.go b/pkg/providers/appsec/data_akamai_appsec_slow_post_protection_settings.go index aa39d1e3c..d86e7221b 100644 --- a/pkg/providers/appsec/data_akamai_appsec_slow_post_protection_settings.go +++ b/pkg/providers/appsec/data_akamai_appsec_slow_post_protection_settings.go @@ -41,7 +41,7 @@ func dataSourceSlowPostProtectionSettings() *schema.Resource { func dataSourceSlowPostProtectionSettingsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSlowPostProtectionSettingsRead") + logger := meta.Log("APPSEC", "dataSourceSlowPostProtectionSettingsRead") getSlowPostProtectionSettings := appsec.GetSlowPostProtectionSettingsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_slowpost_protections.go b/pkg/providers/appsec/data_akamai_appsec_slowpost_protections.go index fc894b1c5..80489084e 100644 --- a/pkg/providers/appsec/data_akamai_appsec_slowpost_protections.go +++ b/pkg/providers/appsec/data_akamai_appsec_slowpost_protections.go @@ -41,7 +41,7 @@ func dataSourceSlowPostProtections() *schema.Resource { func dataSourceSlowPostProtectionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSlowPostProtectionsRead") + logger := meta.Log("APPSEC", "dataSourceSlowPostProtectionsRead") getSlowPostProtections := appsec.GetSlowPostProtectionsRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_version_notes.go b/pkg/providers/appsec/data_akamai_appsec_version_notes.go new file mode 100644 index 000000000..2137d4b18 --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_version_notes.go @@ -0,0 +1,88 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceVersionNotes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceVersionNotesRead, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "json": { + Type: schema.TypeString, + Computed: true, + Description: "JSON List of Notes", + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func dataSourceVersionNotesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "dataSourceVersionNotesRead") + + getVersionNotes := appsec.GetVersionNotesRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getVersionNotes.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getVersionNotes.Version = version + + versionnotes, errr := client.GetVersionNotes(ctx, getVersionNotes) + if errr != nil { + logger.Errorf("calling 'getVersionNotes': %s", errr.Error()) + return diag.FromErr(errr) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "versionNotesDS", versionnotes) + if err == nil { + d.Set("output_text", outputtext) + } + + jsonBody, err := json.Marshal(versionnotes) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("json", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(getVersionNotes.ConfigID)) + + return nil +} diff --git a/pkg/providers/appsec/data_akamai_appsec_version_notes_test.go b/pkg/providers/appsec/data_akamai_appsec_version_notes_test.go new file mode 100644 index 000000000..3fd9de33b --- /dev/null +++ b/pkg/providers/appsec/data_akamai_appsec_version_notes_test.go @@ -0,0 +1,43 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiVersionNotes_data_basic(t *testing.T) { + t.Run("match by VersionNotes ID", func(t *testing.T) { + client := &mockappsec{} + + cv := appsec.GetVersionNotesResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestDSVersionNotes/VersionNotes.json")) + json.Unmarshal([]byte(expectJS), &cv) + + client.On("GetVersionNotes", + mock.Anything, // ctx is irrelevant for this test + appsec.GetVersionNotesRequest{ConfigID: 43253, Version: 7}, + ).Return(&cv, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSVersionNotes/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.akamai_appsec_version_notes.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/data_akamai_appsec_waf_mode.go b/pkg/providers/appsec/data_akamai_appsec_waf_mode.go index cd9f3c72e..9a68fb69c 100644 --- a/pkg/providers/appsec/data_akamai_appsec_waf_mode.go +++ b/pkg/providers/appsec/data_akamai_appsec_waf_mode.go @@ -66,7 +66,7 @@ func dataSourceWAFMode() *schema.Resource { func dataSourceWAFModeRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceWAFModeRead") + logger := meta.Log("APPSEC", "dataSourceWAFModeRead") getWAFMode := appsec.GetWAFModeRequest{} diff --git a/pkg/providers/appsec/data_akamai_appsec_waf_protections.go b/pkg/providers/appsec/data_akamai_appsec_waf_protections.go index 0f1f42e86..35aca4b93 100644 --- a/pkg/providers/appsec/data_akamai_appsec_waf_protections.go +++ b/pkg/providers/appsec/data_akamai_appsec_waf_protections.go @@ -41,7 +41,7 @@ func dataSourceWAFProtections() *schema.Resource { func dataSourceWAFProtectionsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { meta := akamai.Meta(m) client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceWAFProtectionsRead") + logger := meta.Log("APPSEC", "dataSourceWAFProtectionsRead") getWAFProtections := appsec.GetWAFProtectionsRequest{} diff --git a/pkg/providers/appsec/diff_suppress_funcs.go b/pkg/providers/appsec/diff_suppress_funcs.go index a31c9b6f0..fcf518796 100644 --- a/pkg/providers/appsec/diff_suppress_funcs.go +++ b/pkg/providers/appsec/diff_suppress_funcs.go @@ -1,6 +1,7 @@ package appsec import ( + "bytes" "encoding/json" "reflect" "sort" @@ -9,6 +10,33 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +func suppressEquivalentJsonDiffsGeneric(k, old, new string, d *schema.ResourceData) bool { + var ob, nb bytes.Buffer + if err := json.Compact(&ob, []byte(old)); err != nil { + return false + } + + if err := json.Compact(&nb, []byte(new)); err != nil { + return false + } + + return jsonBytesEqual(ob.Bytes(), nb.Bytes()) +} + +func jsonBytesEqual(b1, b2 []byte) bool { + var o1 interface{} + if err := json.Unmarshal(b1, &o1); err != nil { + return false + } + + var o2 interface{} + if err := json.Unmarshal(b2, &o2); err != nil { + return false + } + + return reflect.DeepEqual(o1, o2) +} + func suppressEquivalentJSONDiffs(k, old, new string, d *schema.ResourceData) bool { return compareMatchTargetsJSON(old, new) diff --git a/pkg/providers/appsec/provider.go b/pkg/providers/appsec/provider.go index 286d67251..06ded418c 100644 --- a/pkg/providers/appsec/provider.go +++ b/pkg/providers/appsec/provider.go @@ -61,14 +61,26 @@ func Provider() *schema.Provider { }, }, DataSourcesMap: map[string]*schema.Resource{ + "akamai_appsec_advanced_settings_logging": dataSourceAdvancedSettingsLogging(), + "akamai_appsec_advanced_settings_prefetch": dataSourceAdvancedSettingsPrefetch(), + "akamai_appsec_api_endpoints": dataSourceApiEndpoints(), + "akamai_appsec_hostname_coverage": dataSourceApiHostnameCoverage(), + "akamai_appsec_hostname_coverage_overlapping": dataSourceApiHostnameCoverageOverlapping(), + "akamai_appsec_hostname_coverage_match_targets": dataSourceApiHostnameCoverageMatchTargets(), + "akamai_appsec_api_request_constraints": dataSourceApiRequestConstraints(), + "akamai_appsec_bypass_network_lists": dataSourceBypassNetworkLists(), "akamai_appsec_configuration": dataSourceConfiguration(), "akamai_appsec_configuration_version": dataSourceConfigurationVersion(), + "akamai_appsec_contracts_groups": dataSourceContractsGroups(), + "akamai_appsec_custom_deny": dataSourceCustomDeny(), "akamai_appsec_custom_rules": dataSourceCustomRules(), "akamai_appsec_custom_rule_actions": dataSourceCustomRuleActions(), "akamai_appsec_export_configuration": dataSourceExportConfiguration(), "akamai_appsec_eval": dataSourceEval(), + "akamai_appsec_eval_hostnames": dataSourceEvalHostnames(), "akamai_appsec_eval_rule_actions": dataSourceEvalRuleActions(), "akamai_appsec_eval_rule_condition_exception": dataSourceEvalRuleConditionException(), + "akamai_appsec_failover_hostnames": dataSourceFailoverHostnames(), "akamai_appsec_ip_geo": dataSourceIPGeo(), "akamai_appsec_rule_actions": dataSourceRuleActions(), "akamai_appsec_rule_condition_exception": dataSourceRuleConditionException(), @@ -77,26 +89,35 @@ func Provider() *schema.Provider { "akamai_appsec_security_policy_protections": dataSourcePolicyProtections(), "akamai_appsec_rate_policies": dataSourceRatePolicies(), "akamai_appsec_rate_policy_actions": dataSourceRatePolicyActions(), - "akamai_appsec_rate_protections": dataSourceRateProtections(), - "akamai_appsec_reputation_protections": dataSourceReputationProtections(), + "akamai_appsec_reputation_profile_analysis": dataSourceReputationAnalysis(), "akamai_appsec_reputation_profiles": dataSourceReputationProfiles(), "akamai_appsec_reputation_profile_actions": dataSourceReputationProfileActions(), "akamai_appsec_rule_upgrade_details": dataSourceRuleUpgrade(), "akamai_appsec_selectable_hostnames": dataSourceSelectableHostnames(), "akamai_appsec_security_policy": dataSourceSecurityPolicy(), "akamai_appsec_selected_hostnames": dataSourceSelectedHostnames(), + "akamai_appsec_siem_settings": dataSourceSiemSettings(), + "akamai_appsec_siem_definitions": dataSourceSiemDefinitions(), "akamai_appsec_slow_post": dataSourceSlowPostProtectionSettings(), - "akamai_appsec_slowpost_protections": dataSourceSlowPostProtections(), "akamai_appsec_attack_group_actions": dataSourceAttackGroupActions(), + "akamai_appsec_version_notes": dataSourceVersionNotes(), "akamai_appsec_waf_mode": dataSourceWAFMode(), - "akamai_appsec_waf_protection": dataSourceWAFProtections(), "akamai_appsec_attack_group_condition_exception": dataSourceAttackGroupConditionException(), }, ResourcesMap: map[string]*schema.Resource{ - "akamai_appsec_configuration_version_clone": resourceConfigurationClone(), + "akamai_appsec_advanced_settings_logging": resourceAdvancedSettingsLogging(), + "akamai_appsec_advanced_settings_prefetch": resourceAdvancedSettingsPrefetch(), + "akamai_appsec_api_request_constraints": resourceApiRequestConstraints(), + "akamai_appsec_bypass_network_lists": resourceBypassNetworkLists(), + "akamai_appsec_configuration": resourceConfiguration(), + "akamai_appsec_configuration_clone": resourceConfigurationClone(), + "akamai_appsec_configuration_rename": resourceConfigurationRename(), + "akamai_appsec_configuration_version_clone": resourceConfigurationVersionClone(), "akamai_appsec_selected_hostnames": resourceSelectedHostname(), "akamai_appsec_security_policy_clone": resourceSecurityPolicyClone(), "akamai_appsec_eval": resourceEval(), + "akamai_appsec_eval_hostnames": resourceEvalHost(), + "akamai_appsec_eval_protect_host": resourceEvalProtectHost(), "akamai_appsec_eval_rule_action": resourceEvalRuleAction(), "akamai_appsec_eval_rule_condition_exception": resourceEvalRuleConditionException(), "akamai_appsec_ip_geo": resourceIPGeo(), @@ -106,20 +127,25 @@ func Provider() *schema.Provider { "akamai_appsec_match_target_sequence": resourceMatchTargetSequence(), "akamai_appsec_penalty_box": resourcePenaltyBox(), "akamai_appsec_security_policy_protections": resourcePolicyProtections(), + "akamai_appsec_custom_deny": resourceCustomDeny(), "akamai_appsec_custom_rule": resourceCustomRule(), "akamai_appsec_custom_rule_action": resourceCustomRuleAction(), "akamai_appsec_activations": resourceActivations(), "akamai_appsec_rate_policy": resourceRatePolicy(), "akamai_appsec_rate_policy_action": resourceRatePolicyAction(), "akamai_appsec_rate_protection": resourceRateProtection(), + "akamai_appsec_reputation_profile_analysis": resourceReputationAnalysis(), "akamai_appsec_reputation_protection": resourceReputationProtection(), "akamai_appsec_reputation_profile": resourceReputationProfile(), "akamai_appsec_reputation_profile_action": resourceReputationProfileAction(), "akamai_appsec_rule_upgrade": resourceRuleUpgrade(), "akamai_appsec_security_policy": resourceSecurityPolicy(), + "akamai_appsec_security_policy_rename": resourceSecurityPolicyRename(), + "akamai_appsec_siem_settings": resourceSiemSettings(), "akamai_appsec_slow_post": resourceSlowPostProtectionSetting(), "akamai_appsec_slowpost_protection": resourceSlowPostProtection(), "akamai_appsec_attack_group_action": resourceAttackGroupAction(), + "akamai_appsec_version_notes": resourceVersionNotes(), "akamai_appsec_waf_mode": resourceWAFMode(), "akamai_appsec_waf_protection": resourceWAFProtection(), "akamai_appsec_attack_group_condition_exception": resourceAttackGroupConditionException(), diff --git a/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging.go b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging.go new file mode 100644 index 000000000..551e75247 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging.go @@ -0,0 +1,263 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceAdvancedSettingsLogging() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAdvancedSettingsLoggingUpdate, + ReadContext: resourceAdvancedSettingsLoggingRead, + UpdateContext: resourceAdvancedSettingsLoggingUpdate, + DeleteContext: resourceAdvancedSettingsLoggingDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Optional: true, + }, + "logging": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + }, + }, + } +} + +func resourceAdvancedSettingsLoggingRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsLoggingRead") + + getAdvancedSettingsLogging := appsec.GetAdvancedSettingsLoggingRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAdvancedSettingsLogging.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAdvancedSettingsLogging.Version = version + + if len(s) >= 3 { + policyid := s[2] + + getAdvancedSettingsLogging.PolicyID = policyid + } + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsLogging.PolicyID = policyid + } + advancedsettingslogging, err := client.GetAdvancedSettingsLogging(ctx, getAdvancedSettingsLogging) + if err != nil { + logger.Errorf("calling 'getAdvancedSettingsLogging': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "advancedSettingsLoggingDS", advancedsettingslogging) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getAdvancedSettingsLogging.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getAdvancedSettingsLogging.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getAdvancedSettingsLogging.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + jsonBody, err := json.Marshal(advancedsettingslogging) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("logging", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getAdvancedSettingsLogging.ConfigID, getAdvancedSettingsLogging.Version, getAdvancedSettingsLogging.PolicyID)) + + return nil +} + +func resourceAdvancedSettingsLoggingDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsLoggingRemove") + + removeAdvancedSettingsLogging := appsec.RemoveAdvancedSettingsLoggingRequest{} + + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAdvancedSettingsLogging.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAdvancedSettingsLogging.Version = version + + if len(s) >= 3 { + policyid := s[2] + + removeAdvancedSettingsLogging.PolicyID = policyid + } + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAdvancedSettingsLogging.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAdvancedSettingsLogging.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAdvancedSettingsLogging.PolicyID = policyid + } + + if removeAdvancedSettingsLogging.PolicyID != "" { + removeAdvancedSettingsLogging.Override = false + } else { + removeAdvancedSettingsLogging.AllowSampling = false + } + + _, erru := client.RemoveAdvancedSettingsLogging(ctx, removeAdvancedSettingsLogging) + if erru != nil { + logger.Errorf("calling 'updateAdvancedSettingsLogging': %s", erru.Error()) + return diag.FromErr(erru) + } + d.SetId("") + return nil +} + +func resourceAdvancedSettingsLoggingUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsLoggingUpdate") + + updateAdvancedSettingsLogging := appsec.UpdateAdvancedSettingsLoggingRequest{} + + jsonpostpayload := d.Get("logging") + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + + updateAdvancedSettingsLogging.JsonPayloadRaw = rawJSON + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsLogging.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsLogging.Version = version + + if len(s) >= 3 { + policyid := s[2] + + updateAdvancedSettingsLogging.PolicyID = policyid + } + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsLogging.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsLogging.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsLogging.PolicyID = policyid + } + _, erru := client.UpdateAdvancedSettingsLogging(ctx, updateAdvancedSettingsLogging) + if erru != nil { + logger.Errorf("calling 'updateAdvancedSettingsLogging': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceAdvancedSettingsLoggingRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging_test.go b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging_test.go new file mode 100644 index 000000000..39df02785 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_logging_test.go @@ -0,0 +1,62 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiAdvancedSettingsLogging_res_basic(t *testing.T) { + t.Run("match by AdvancedSettingsLogging ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateAdvancedSettingsLoggingResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetAdvancedSettingsLoggingResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveAdvancedSettingsLoggingResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("GetAdvancedSettingsLogging", + mock.Anything, // ctx is irrelevant for this test + appsec.GetAdvancedSettingsLoggingRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateAdvancedSettingsLogging", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateAdvancedSettingsLoggingRequest{ConfigID: 43253, Version: 7, PolicyID: "", JsonPayloadRaw: json.RawMessage{0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x6c, 0x6c, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x73, 0x64, 0x61, 0x73, 0x64, 0x61, 0x64, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6f, 0x6e, 0x6c, 0x79, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x7d, 0xa}}, + ).Return(&cu, nil) + + client.On("RemoveAdvancedSettingsLogging", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveAdvancedSettingsLoggingRequest{ConfigID: 43253, Version: 7, PolicyID: ""}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResAdvancedSettingsLogging/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_advanced_settings_logging.test", "id", "43253:7:"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch.go b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch.go new file mode 100644 index 000000000..c860aa90d --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch.go @@ -0,0 +1,248 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceAdvancedSettingsPrefetch() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAdvancedSettingsPrefetchUpdate, + ReadContext: resourceAdvancedSettingsPrefetchRead, + UpdateContext: resourceAdvancedSettingsPrefetchUpdate, + DeleteContext: resourceAdvancedSettingsPrefetchDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "enable_app_layer": { + Type: schema.TypeBool, + Required: true, + }, + "all_extensions": { + Type: schema.TypeBool, + Required: true, + }, + "enable_rate_controls": { + Type: schema.TypeBool, + Required: true, + }, + "extensions": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of extensions", + }, + }, + } +} + +func resourceAdvancedSettingsPrefetchRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsPrefetchRead") + + getAdvancedSettingsPrefetch := appsec.GetAdvancedSettingsPrefetchRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAdvancedSettingsPrefetch.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAdvancedSettingsPrefetch.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsPrefetch.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAdvancedSettingsPrefetch.Version = version + } + prefetchget, err := client.GetAdvancedSettingsPrefetch(ctx, getAdvancedSettingsPrefetch) + if err != nil { + logger.Errorf("calling 'getAdvancedSettingsPrefetch': %s", err.Error()) + return diag.FromErr(err) + } + + if err := d.Set("config_id", getAdvancedSettingsPrefetch.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getAdvancedSettingsPrefetch.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("enable_app_layer", prefetchget.EnableAppLayer); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("all_extensions", prefetchget.AllExtensions); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + if err := d.Set("enable_rate_controls", prefetchget.EnableRateControls); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + if err := d.Set("extensions", prefetchget.Extensions); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getAdvancedSettingsPrefetch.ConfigID, getAdvancedSettingsPrefetch.Version)) + + return nil +} + +func resourceAdvancedSettingsPrefetchDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsPrefetchRemove") + + updateAdvancedSettingsPrefetch := appsec.UpdateAdvancedSettingsPrefetchRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsPrefetch.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsPrefetch.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.Version = version + } + updateAdvancedSettingsPrefetch.EnableAppLayer = false + + updateAdvancedSettingsPrefetch.EnableRateControls = false + + _, erru := client.UpdateAdvancedSettingsPrefetch(ctx, updateAdvancedSettingsPrefetch) + if erru != nil { + logger.Errorf("calling 'removeAdvancedSettingsPrefetch': %s", erru.Error()) + return diag.FromErr(erru) + } + + d.SetId("") + return nil +} + +func resourceAdvancedSettingsPrefetchUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceAdvancedSettingsPrefetchUpdate") + + updateAdvancedSettingsPrefetch := appsec.UpdateAdvancedSettingsPrefetchRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsPrefetch.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAdvancedSettingsPrefetch.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.Version = version + } + enableAppLayer, err := tools.GetBoolValue("enable_app_layer", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.EnableAppLayer = enableAppLayer + + allExtensions, err := tools.GetBoolValue("all_extensions", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.AllExtensions = allExtensions + + enableRateControls, err := tools.GetBoolValue("enable_rate_controls", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAdvancedSettingsPrefetch.EnableRateControls = enableRateControls + + extensions := d.Get("extensions").([]interface{}) + exts := make([]string, 0, len(extensions)) + + for _, h := range extensions { + exts = append(exts, h.(string)) + + } + + updateAdvancedSettingsPrefetch.Extensions = exts + + logger.Errorf("calling 'getAdvancedSettingsPrefetch': Extensions %v", updateAdvancedSettingsPrefetch.Extensions) + + _, erru := client.UpdateAdvancedSettingsPrefetch(ctx, updateAdvancedSettingsPrefetch) + if erru != nil { + logger.Errorf("calling 'updateAdvancedSettingsPrefetch': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceAdvancedSettingsPrefetchRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch_test.go b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch_test.go new file mode 100644 index 000000000..b554eef2d --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_advanced_settings_prefetch_test.go @@ -0,0 +1,52 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiAdvancedSettingsPrefetch_res_basic(t *testing.T) { + t.Run("match by AdvancedSettingsPrefetch ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateAdvancedSettingsPrefetchResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetAdvancedSettingsPrefetchResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json")) + json.Unmarshal([]byte(expectJS), &cr) + + client.On("GetAdvancedSettingsPrefetch", + mock.Anything, // ctx is irrelevant for this test + appsec.GetAdvancedSettingsPrefetchRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateAdvancedSettingsPrefetch", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateAdvancedSettingsPrefetchRequest{ConfigID: 43253, Version: 7, AllExtensions: true, EnableAppLayer: false, EnableRateControls: false, Extensions: []string{"cgi", "jsp", "aspx", "EMPTY_STRING", "php", "py", "asp"}}, + ).Return(&cu, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: false, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResAdvancedSettingsPrefetch/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_advanced_settings_prefetch.test", "id", "43253"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints.go b/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints.go new file mode 100644 index 000000000..97fa32ace --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints.go @@ -0,0 +1,336 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceApiRequestConstraints() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceApiRequestConstraintsUpdate, + ReadContext: resourceApiRequestConstraintsRead, + UpdateContext: resourceApiRequestConstraintsUpdate, + DeleteContext: resourceApiRequestConstraintsDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Required: true, + }, + "action": { + Type: schema.TypeString, + Required: true, + ValidateFunc: ValidateActions, + }, + "api_endpoint_id": { + Type: schema.TypeInt, + Optional: true, + }, + }, + } +} + +func resourceApiRequestConstraintsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceApiRequestConstraintsRead") + + getApiRequestConstraints := appsec.GetApiRequestConstraintsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getApiRequestConstraints.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getApiRequestConstraints.Version = version + + policyid := s[2] + getApiRequestConstraints.PolicyID = policyid + + if len(s) >= 4 { + apiID, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getApiRequestConstraints.ApiID = apiID + } + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.PolicyID = policyid + + ApiID, err := tools.GetIntValue("api_endpoint_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getApiRequestConstraints.ApiID = ApiID + } + response, err := client.GetApiRequestConstraints(ctx, getApiRequestConstraints) + if err != nil { + logger.Errorf("calling 'getApiRequestConstraints': %s", err.Error()) + return diag.FromErr(err) + } + + if err := d.Set("config_id", getApiRequestConstraints.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getApiRequestConstraints.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getApiRequestConstraints.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("api_endpoint_id", getApiRequestConstraints.ApiID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if getApiRequestConstraints.ApiID != 0 { + if len(response.APIEndpoints) > 0 { + for _, val := range response.APIEndpoints { + if val.ID == getApiRequestConstraints.ApiID { + if err := d.Set("action", val.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } + } + } + } + if getApiRequestConstraints.ApiID != 0 { + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getApiRequestConstraints.ConfigID, getApiRequestConstraints.Version, getApiRequestConstraints.PolicyID, getApiRequestConstraints.ApiID)) + } else { + d.SetId(fmt.Sprintf("%d:%d:%s", getApiRequestConstraints.ConfigID, getApiRequestConstraints.Version, getApiRequestConstraints.PolicyID)) + } + return nil +} + +func resourceApiRequestConstraintsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceApiRequestConstraintsRemove") + + getPolicyProtections := appsec.GetPolicyProtectionsRequest{} + removeApiRequestConstraints := appsec.RemoveApiRequestConstraintsRequest{} + removePolicyProtections := appsec.RemovePolicyProtectionsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPolicyProtections.ConfigID = configid + removeApiRequestConstraints.ConfigID = configid + removePolicyProtections.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPolicyProtections.Version = version + removeApiRequestConstraints.Version = version + removePolicyProtections.Version = version + + policyid := s[2] + + getPolicyProtections.PolicyID = policyid + removeApiRequestConstraints.PolicyID = policyid + removePolicyProtections.PolicyID = policyid + + if len(s) >= 4 { + apiID, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + + removeApiRequestConstraints.ApiID = apiID + + } + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + + getPolicyProtections.ConfigID = configid + removeApiRequestConstraints.ConfigID = configid + removePolicyProtections.ConfigID = configid + + getPolicyProtections.Version = version + removeApiRequestConstraints.Version = version + removePolicyProtections.Version = version + + getPolicyProtections.PolicyID = policyid + removeApiRequestConstraints.PolicyID = policyid + removePolicyProtections.PolicyID = policyid + } + policyprotections, err := client.GetPolicyProtections(ctx, getPolicyProtections) + if err != nil { + logger.Errorf("calling 'getPolicyProtections': %s", err.Error()) + return diag.FromErr(err) + } + + apiEndpointID, err := tools.GetIntValue("api_endpoint_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeApiRequestConstraints.ApiID = apiEndpointID + + if removeApiRequestConstraints.ApiID == 0 { + if policyprotections.ApplyAPIConstraints == true { + removePolicyProtections.ApplyAPIConstraints = false + removePolicyProtections.ApplyApplicationLayerControls = policyprotections.ApplyApplicationLayerControls + removePolicyProtections.ApplyBotmanControls = policyprotections.ApplyBotmanControls + removePolicyProtections.ApplyNetworkLayerControls = policyprotections.ApplyNetworkLayerControls + removePolicyProtections.ApplyRateControls = policyprotections.ApplyRateControls + removePolicyProtections.ApplyReputationControls = policyprotections.ApplyReputationControls + removePolicyProtections.ApplySlowPostControls = policyprotections.ApplySlowPostControls + + _, errd := client.RemovePolicyProtections(ctx, removePolicyProtections) + if errd != nil { + logger.Errorf("calling 'removePolicyProtections': %s", errd.Error()) + return diag.FromErr(errd) + } + } + } else { + removeApiRequestConstraints.Action = "none" + _, erru := client.RemoveApiRequestConstraints(ctx, removeApiRequestConstraints) + if erru != nil { + logger.Errorf("calling 'removeApiRequestConstraints': %s", erru.Error()) + return diag.FromErr(erru) + } + } + + d.SetId("") + return nil +} + +func resourceApiRequestConstraintsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceApiRequestConstraintsUpdate") + + updateApiRequestConstraints := appsec.UpdateApiRequestConstraintsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateApiRequestConstraints.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateApiRequestConstraints.Version = version + + policyid := s[2] + + updateApiRequestConstraints.PolicyID = policyid + + if len(s) >= 4 { + apiID, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + + updateApiRequestConstraints.ApiID = apiID + } + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateApiRequestConstraints.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateApiRequestConstraints.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateApiRequestConstraints.PolicyID = policyid + + apiEndpointID, err := tools.GetIntValue("api_endpoint_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateApiRequestConstraints.ApiID = apiEndpointID + } + action, err := tools.GetStringValue("action", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateApiRequestConstraints.Action = action + + _, erru := client.UpdateApiRequestConstraints(ctx, updateApiRequestConstraints) + if erru != nil { + logger.Errorf("calling 'updateApiRequestConstraints': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceApiRequestConstraintsRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints_test.go b/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints_test.go new file mode 100644 index 000000000..70b495298 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_api_request_constraints_test.go @@ -0,0 +1,70 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiApiRequestConstraints_res_basic(t *testing.T) { + t.Run("match by ApiRequestConstraints ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateApiRequestConstraintsResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResApiRequestConstraints/ApiRequestConstraints.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetApiRequestConstraintsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResApiRequestConstraints/ApiRequestConstraints.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveApiRequestConstraintsResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResApiRequestConstraints/ApiRequestConstraints.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + crp := appsec.GetPolicyProtectionsResponse{} + expectJSP := compactJSON(loadFixtureBytes("testdata/TestDSPolicyProtections/PolicyProtections.json")) + json.Unmarshal([]byte(expectJSP), &crp) + + client.On("GetApiRequestConstraints", + mock.Anything, // ctx is irrelevant for this test + appsec.GetApiRequestConstraintsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", ApiID: 1}, + ).Return(&cr, nil) + + client.On("UpdateApiRequestConstraints", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateApiRequestConstraintsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", ApiID: 1, Action: "alert"}, + ).Return(&cu, nil) + + client.On("GetPolicyProtections", + mock.Anything, // ctx is irrelevant for this test + appsec.GetPolicyProtectionsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230"}, + ).Return(&crp, nil) + + client.On("RemoveApiRequestConstraints", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveApiRequestConstraintsRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", ApiID: 1, Action: "none"}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResApiRequestConstraints/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_api_request_constraints.test", "id", "43253:7:AAAA_81230:1"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_attack_group_action.go b/pkg/providers/appsec/resource_akamai_appsec_attack_group_action.go index 849c8aafb..6e1b2de71 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_attack_group_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_attack_group_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -48,11 +49,6 @@ func resourceAttackGroupAction() *schema.Resource { Required: true, ValidateFunc: ValidateActions, }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -63,48 +59,81 @@ func resourceAttackGroupActionRead(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceAttackGroupActionRead") getAttackGroupAction := appsec.GetAttackGroupActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAttackGroupAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAttackGroupAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupAction.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupAction.Group = attackgroup + getAttackGroupAction.PolicyID = policyid + + attackgroup := s[3] + + getAttackGroupAction.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupAction.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupAction.PolicyID = policyid + + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupAction.Group = attackgroup + } attackgroupaction, err := client.GetAttackGroupAction(ctx, getAttackGroupAction) if err != nil { logger.Errorf("calling 'getAttackGroupAction': %s", err.Error()) return diag.FromErr(err) } - ots := OutputTemplates{} - InitTemplates(ots) + if err := d.Set("config_id", getAttackGroupAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getAttackGroupAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "AttackGroupActionDS", attackgroupaction) - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("security_policy_id", getAttackGroupAction.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("attack_group", getAttackGroupAction.Group); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getAttackGroupAction.ConfigID)) + if err := d.Set("attack_group_action", attackgroupaction.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s:%s", getAttackGroupAction.ConfigID, getAttackGroupAction.Version, getAttackGroupAction.PolicyID, getAttackGroupAction.Group)) return nil } @@ -116,31 +145,54 @@ func resourceAttackGroupActionDelete(ctx context.Context, d *schema.ResourceData logger := meta.Log("APPSEC", "resourceAttackGroupActionRemove") removeAttackGroupAction := appsec.UpdateAttackGroupActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAttackGroupAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAttackGroupAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupAction.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupAction.Group = attackgroup + removeAttackGroupAction.PolicyID = policyid + + attackgroup := s[3] + + removeAttackGroupAction.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupAction.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupAction.PolicyID = policyid + + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupAction.Group = attackgroup + } removeAttackGroupAction.Action = "none" _, erru := client.UpdateAttackGroupAction(ctx, removeAttackGroupAction) @@ -159,31 +211,54 @@ func resourceAttackGroupActionUpdate(ctx context.Context, d *schema.ResourceData logger := meta.Log("APPSEC", "resourceAttackGroupActionUpdate") updateAttackGroupAction := appsec.UpdateAttackGroupActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAttackGroupAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAttackGroupAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupAction.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupAction.Group = attackgroup + updateAttackGroupAction.PolicyID = policyid + attackgroup := s[3] + + updateAttackGroupAction.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupAction.PolicyID = policyid + + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupAction.Group = attackgroup + } attackgroupaction, err := tools.GetStringValue("attack_group_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_attack_group_action_test.go b/pkg/providers/appsec/resource_akamai_appsec_attack_group_action_test.go index cc1786937..2baf7df9b 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_attack_group_action_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_attack_group_action_test.go @@ -39,8 +39,9 @@ func TestAccAkamaiAttackGroupAction_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResAttackGroupAction/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_attack_group_action.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_attack_group_action.test", "id", "43253:7:AAAA_81230:SQL"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception.go b/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception.go index 989b95bd4..1f7bbafb7 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception.go +++ b/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -45,14 +46,10 @@ func resourceAttackGroupConditionException() *schema.Resource { Required: true, }, "condition_exception": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsJSON, - }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentJsonDiffsGeneric, }, }, } @@ -64,49 +61,85 @@ func resourceAttackGroupConditionExceptionRead(ctx context.Context, d *schema.Re logger := meta.Log("APPSEC", "resourceAttackGroupConditionExceptionRead") getAttackGroupConditionException := appsec.GetAttackGroupConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAttackGroupConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getAttackGroupConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupConditionException.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getAttackGroupConditionException.Group = attackgroup + getAttackGroupConditionException.PolicyID = policyid + + attackgroup := s[3] + + getAttackGroupConditionException.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupConditionException.PolicyID = policyid + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getAttackGroupConditionException.Group = attackgroup + } attackgroupconditionexception, err := client.GetAttackGroupConditionException(ctx, getAttackGroupConditionException) if err != nil { logger.Errorf("calling 'getAttackGroupConditionException': %s", err.Error()) return diag.FromErr(err) } - ots := OutputTemplates{} - InitTemplates(ots) + if err := d.Set("config_id", getAttackGroupConditionException.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "AttackGroupConditionExceptions", attackgroupconditionexception) + if err := d.Set("version", getAttackGroupConditionException.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("security_policy_id", getAttackGroupConditionException.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("attack_group", getAttackGroupConditionException.Group); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + jsonBody, err := json.Marshal(attackgroupconditionexception) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("condition_exception", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getAttackGroupConditionException.ConfigID)) + d.SetId(fmt.Sprintf("%d:%d:%s:%s", getAttackGroupConditionException.ConfigID, getAttackGroupConditionException.Version, getAttackGroupConditionException.PolicyID, getAttackGroupConditionException.Group)) return nil } @@ -118,33 +151,54 @@ func resourceAttackGroupConditionExceptionDelete(ctx context.Context, d *schema. logger := meta.Log("APPSEC", "resourceAttackGroupConditionExceptionRemove") removeAttackGroupConditionException := appsec.RemoveAttackGroupConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAttackGroupConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeAttackGroupConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupConditionException.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeAttackGroupConditionException.Group = attackgroup + removeAttackGroupConditionException.PolicyID = policyid + + attackgroup := s[3] + + removeAttackGroupConditionException.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupConditionException.ConfigID = configid - logger.Errorf("calling 'RemoveAttackGroupConditionException': %v", removeAttackGroupConditionException) + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupConditionException.PolicyID = policyid + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeAttackGroupConditionException.Group = attackgroup + } _, errd := client.RemoveAttackGroupConditionException(ctx, removeAttackGroupConditionException) if errd != nil { logger.Errorf("calling 'RemoveAttackGroupConditionException': %s", errd.Error()) @@ -163,40 +217,62 @@ func resourceAttackGroupConditionExceptionUpdate(ctx context.Context, d *schema. updateAttackGroupConditionException := appsec.UpdateAttackGroupConditionExceptionRequest{} jsonpostpayload := d.Get("condition_exception") + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &updateAttackGroupConditionException); err != nil { - return diag.FromErr(err) - } + updateAttackGroupConditionException.JsonPayloadRaw = rawJSON + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAttackGroupConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateAttackGroupConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupConditionException.PolicyID = policyid + policyid := s[2] - attackgroup, err := tools.GetStringValue("attack_group", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateAttackGroupConditionException.Group = attackgroup + updateAttackGroupConditionException.PolicyID = policyid + + attackgroup := s[3] - resp, erru := client.UpdateAttackGroupConditionException(ctx, updateAttackGroupConditionException) + updateAttackGroupConditionException.Group = attackgroup + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupConditionException.PolicyID = policyid + + attackgroup, err := tools.GetStringValue("attack_group", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateAttackGroupConditionException.Group = attackgroup + } + _, erru := client.UpdateAttackGroupConditionException(ctx, updateAttackGroupConditionException) if erru != nil { logger.Errorf("calling 'updateAttackGroupConditionException': %s", erru.Error()) return diag.FromErr(erru) } - logger.Warnf("calling 'updateAttackGroupConditionException': %s", resp) return resourceAttackGroupConditionExceptionRead(ctx, d, m) } diff --git a/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception_test.go b/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception_test.go index 0efa3cc6d..3b18c18e7 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_attack_group_condition_exception_test.go @@ -37,28 +37,7 @@ func TestAccAkamaiAttackGroupConditionException_res_basic(t *testing.T) { client.On("UpdateAttackGroupConditionException", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateAttackGroupConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", Group: "SQL", Conditions: []struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{}, Exception: struct { - HeaderCookieOrParamValues []string "json:\"headerCookieOrParamValues\"" - SpecificHeaderCookieOrParamNames []struct { - Names []string "json:\"names,omitempty\"" - Selector string "json:\"selector,omitempty\"" - } "json:\"specificHeaderCookieOrParamNames,omitempty\"" - SpecificHeaderCookieOrParamPrefix struct { - Prefix string "json:\"prefix,omitempty\"" - Selector string "json:\"selector,omitempty\"" - } "json:\"specificHeaderCookieOrParamPrefix,omitempty\"" - }{HeaderCookieOrParamValues: []string{"abc"}, SpecificHeaderCookieOrParamNames: []struct { - Names []string "json:\"names,omitempty\"" - Selector string "json:\"selector,omitempty\"" - }(nil), SpecificHeaderCookieOrParamPrefix: struct { - Prefix string "json:\"prefix,omitempty\"" - Selector string "json:\"selector,omitempty\"" - }{Prefix: "a*", Selector: "REQUEST_COOKIES"}}}, + appsec.UpdateAttackGroupConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", Group: "SQL", JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x62, 0x63, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x2a, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x43, 0x4f, 0x4f, 0x4b, 0x49, 0x45, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x7d, 0xa}}, ).Return(&cu, nil) useClient(client, func() { @@ -69,8 +48,9 @@ func TestAccAkamaiAttackGroupConditionException_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResAttackGroupConditionException/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_attack_group_condition_exception.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_attack_group_condition_exception.test", "id", "43253:7:AAAA_81230:SQL"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists.go b/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists.go new file mode 100644 index 000000000..2e279da96 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists.go @@ -0,0 +1,212 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceBypassNetworkLists() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceBypassNetworkListsUpdate, + ReadContext: resourceBypassNetworkListsRead, + UpdateContext: resourceBypassNetworkListsUpdate, + DeleteContext: resourceBypassNetworkListsDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "bypass_network_list": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func resourceBypassNetworkListsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceBypassNetworkListsRead") + + getBypassNetworkLists := appsec.GetBypassNetworkListsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getBypassNetworkLists.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getBypassNetworkLists.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getBypassNetworkLists.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getBypassNetworkLists.Version = version + } + bypassnetworklists, err := client.GetBypassNetworkLists(ctx, getBypassNetworkLists) + if err != nil { + logger.Errorf("calling 'getBypassNetworkLists': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "bypassNetworkListsDS", bypassnetworklists) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getBypassNetworkLists.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getBypassNetworkLists.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getBypassNetworkLists.ConfigID, getBypassNetworkLists.Version)) + + return nil +} + +func resourceBypassNetworkListsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceBypassNetworkListsRemove") + + removeBypassNetworkLists := appsec.RemoveBypassNetworkListsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeBypassNetworkLists.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeBypassNetworkLists.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeBypassNetworkLists.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeBypassNetworkLists.Version = version + } + hn := make([]string, 0, 1) + + removeBypassNetworkLists.NetworkLists = hn + + _, erru := client.RemoveBypassNetworkLists(ctx, removeBypassNetworkLists) + if erru != nil { + logger.Errorf("calling 'removeBypassNetworkLists': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceBypassNetworkListsRead(ctx, d, m) +} + +func resourceBypassNetworkListsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceBypassNetworkListsUpdate") + + updateBypassNetworkLists := appsec.UpdateBypassNetworkListsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateBypassNetworkLists.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateBypassNetworkLists.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateBypassNetworkLists.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateBypassNetworkLists.Version = version + } + netlist := d.Get("bypass_network_list").([]interface{}) + nru := make([]string, 0, len(netlist)) + + for _, h := range netlist { + nru = append(nru, h.(string)) + + } + updateBypassNetworkLists.NetworkLists = nru + + _, erru := client.UpdateBypassNetworkLists(ctx, updateBypassNetworkLists) + if erru != nil { + logger.Errorf("calling 'updateBypassNetworkLists': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceBypassNetworkListsRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists_test.go b/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists_test.go new file mode 100644 index 000000000..cee6183f6 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_bypass_network_lists_test.go @@ -0,0 +1,61 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiBypassNetworkLists_res_basic(t *testing.T) { + t.Run("match by BypassNetworkLists ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateBypassNetworkListsResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResBypassNetworkLists/BypassNetworkLists.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetBypassNetworkListsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResBypassNetworkLists/BypassNetworkLists.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveBypassNetworkListsResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResBypassNetworkLists/BypassNetworkLists.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("GetBypassNetworkLists", + mock.Anything, // ctx is irrelevant for this test + appsec.GetBypassNetworkListsRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateBypassNetworkLists", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateBypassNetworkListsRequest{ConfigID: 43253, Version: 7, NetworkLists: []string{"888518_ACDDCKERS", "1304427_AAXXBBLIST"}}, + ).Return(&cu, nil) + + client.On("RemoveBypassNetworkLists", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveBypassNetworkListsRequest{ConfigID: 43253, Version: 7, NetworkLists: []string{}}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResBypassNetworkLists/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_bypass_network_lists.test", "id", "43253:7"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration.go b/pkg/providers/appsec/resource_akamai_appsec_configuration.go new file mode 100644 index 000000000..852804acd --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration.go @@ -0,0 +1,232 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceConfiguration() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceConfigurationCreate, + ReadContext: resourceConfigurationRead, + UpdateContext: resourceConfigurationUpdate, + DeleteContext: resourceConfigurationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Required: true, + }, + "contract_id": { + Type: schema.TypeString, + Required: true, + }, + "group_id": { + Type: schema.TypeInt, + Required: true, + }, + "host_names": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "config_id": { + Type: schema.TypeInt, + Computed: true, + }, + "version": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func resourceConfigurationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationCreate") + + createConfiguration := appsec.CreateConfigurationRequest{} + + name, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfiguration.Name = name + + description, err := tools.GetStringValue("description", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfiguration.Description = description + + contractID, err := tools.GetStringValue("contract_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfiguration.ContractID = contractID + + groupID, err := tools.GetIntValue("group_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfiguration.GroupID = groupID + + hostnamelist := d.Get("host_names").([]interface{}) + hnl := make([]string, 0, len(hostnamelist)) + + for _, h := range hostnamelist { + hnl = append(hnl, h.(string)) + + } + createConfiguration.Hostnames = hnl + + postresp, errc := client.CreateConfiguration(ctx, createConfiguration) + if errc != nil { + logger.Errorf("calling 'createConfiguration': %s", errc.Error()) + return diag.FromErr(errc) + } + + if err := d.Set("config_id", postresp.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", postresp.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(strconv.Itoa(postresp.ConfigID)) + + return resourceConfigurationRead(ctx, d, m) +} + +func resourceConfigurationUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationUpdate") + + updateConfiguration := appsec.UpdateConfigurationRequest{} + + ID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + updateConfiguration.ConfigID = ID + + name, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateConfiguration.Name = name + + description, err := tools.GetStringValue("description", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateConfiguration.Description = description + + _, erru := client.UpdateConfiguration(ctx, updateConfiguration) + if erru != nil { + logger.Errorf("calling 'updateConfiguration': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceConfigurationRead(ctx, d, m) +} + +func resourceConfigurationDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationRemove") + + removeConfiguration := appsec.RemoveConfigurationRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeConfiguration.ConfigID = configid + + _, errd := client.RemoveConfiguration(ctx, removeConfiguration) + if errd != nil { + logger.Errorf("calling 'removeConfiguration': %s", errd.Error()) + return diag.FromErr(errd) + } + + d.SetId("") + + return nil +} + +func resourceConfigurationRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationRead") + + getConfiguration := appsec.GetConfigurationsRequest{} + + ID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getConfiguration.ConfigID = ID + + configName, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getConfiguration.Name = configName + + configuration, err := client.GetConfigurations(ctx, getConfiguration) + if err != nil { + logger.Errorf("calling 'getConfiguration': %s", err.Error()) + return diag.FromErr(err) + } + + var configlist string + var configidfound int + configlist = configlist + " ConfigID Name VersionList" + "\n" + + for _, configval := range configuration.Configurations { + + if configval.Name == configName { + d.Set("config_id", configval.ID) + d.Set("latest_version", configval.LatestVersion) + d.Set("staging_version", configval.StagingVersion) + d.Set("production_version", configval.ProductionVersion) + configidfound = configval.ID + } + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "configuration", configuration) + if err == nil { + d.Set("output_text", outputtext) + } + + d.SetId(strconv.Itoa(configidfound)) + + return nil +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_clone.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_clone.go index c329c112d..47467562c 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_configuration_clone.go +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_clone.go @@ -23,7 +23,28 @@ func resourceConfigurationClone() *schema.Resource { UpdateContext: resourceConfigurationCloneUpdate, DeleteContext: resourceConfigurationCloneDelete, Schema: map[string]*schema.Schema{ - "config_id": { + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Required: true, + }, + "contract_id": { + Type: schema.TypeString, + Required: true, + }, + "group_id": { + Type: schema.TypeInt, + Required: true, + }, + "host_names": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "create_from_config_id": { Type: schema.TypeInt, Required: true, }, @@ -31,11 +52,10 @@ func resourceConfigurationClone() *schema.Resource { Type: schema.TypeInt, Required: true, }, - - "rule_update": { - Type: schema.TypeBool, - Optional: true, - Default: false, + "config_id": { + Type: schema.TypeInt, + Computed: true, + Description: "Config id of cloned configuration", }, "version": { Type: schema.TypeInt, @@ -53,29 +73,66 @@ func resourceConfigurationCloneCreate(ctx context.Context, d *schema.ResourceDat createConfigurationClone := appsec.CreateConfigurationCloneRequest{} - configid, err := tools.GetIntValue("config_id", d) + createFromConfigID, err := tools.GetIntValue("create_from_config_id", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) } - createConfigurationClone.ConfigID = configid + createConfigurationClone.CreateFrom.ConfigID = createFromConfigID version, err := tools.GetIntValue("create_from_version", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) } - createConfigurationClone.CreateFromVersion = version + createConfigurationClone.CreateFrom.Version = version + + name, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfigurationClone.Name = name + + description, err := tools.GetStringValue("description", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfigurationClone.Description = description + + contractID, err := tools.GetStringValue("contract_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfigurationClone.ContractID = contractID + + groupID, err := tools.GetIntValue("group_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createConfigurationClone.GroupID = groupID + + hostnamelist := d.Get("host_names").([]interface{}) + hnl := make([]string, 0, len(hostnamelist)) + + for _, h := range hostnamelist { + hnl = append(hnl, h.(string)) + + } + createConfigurationClone.Hostnames = hnl ccr, err := client.CreateConfigurationClone(ctx, createConfigurationClone) if err != nil { logger.Errorf("calling 'createConfigurationClone': %s", err.Error()) return diag.FromErr(err) } - logger.Errorf("calling 'createConfigurationClone CCR ': %v", ccr) + //logger.Errorf("calling 'createConfigurationClone CCR ': %v", ccr) if err := d.Set("version", ccr.Version); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } + if err := d.Set("config_id", ccr.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(strconv.Itoa(ccr.ConfigID)) return resourceConfigurationCloneRead(ctx, d, m) @@ -100,21 +157,43 @@ func resourceConfigurationCloneRead(ctx context.Context, d *schema.ResourceData, } getConfigurationClone.Version = version - configurationclone, err := client.GetConfigurationClone(ctx, getConfigurationClone) + Configurationclone, err := client.GetConfigurationClone(ctx, getConfigurationClone) if err != nil { logger.Errorf("calling 'getConfigurationClone': %s", err.Error()) return diag.FromErr(err) } - d.SetId(strconv.Itoa(configurationclone.ConfigID)) + d.SetId(strconv.Itoa(Configurationclone.ConfigID)) return nil } func resourceConfigurationCloneDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - return schema.NoopContext(nil, d, m) + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationRemove") + + removeConfiguration := appsec.RemoveConfigurationRequest{} + + configid, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + removeConfiguration.ConfigID = configid + + _, errd := client.RemoveConfiguration(ctx, removeConfiguration) + if errd != nil { + logger.Errorf("calling 'removeConfiguration': %s", errd.Error()) + return diag.FromErr(errd) + } + + d.SetId("") + + return nil } func resourceConfigurationCloneUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - return schema.NoopContext(nil, d, m) + //return schema.NoopContext(nil, d, m) + return resourceConfigurationCloneRead(ctx, d, m) } diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_clone_test.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_clone_test.go index 8f00105d5..4fc0a8f53 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_configuration_clone_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_clone_test.go @@ -21,6 +21,10 @@ func TestAccAkamaiConfigurationClone_res_basic(t *testing.T) { expectJS := compactJSON(loadFixtureBytes("testdata/TestResConfigurationClone/ConfigurationClone.json")) json.Unmarshal([]byte(expectJS), &cr) + crd := appsec.RemoveConfigurationResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResConfigurationClone/ConfigurationClone.json")) + json.Unmarshal([]byte(expectJSD), &crd) + client.On("GetConfigurationClone", mock.Anything, // ctx is irrelevant for this test appsec.GetConfigurationCloneRequest{ConfigID: 43253, Version: 15}, @@ -28,9 +32,17 @@ func TestAccAkamaiConfigurationClone_res_basic(t *testing.T) { client.On("CreateConfigurationClone", mock.Anything, // ctx is irrelevant for this test - appsec.CreateConfigurationCloneRequest{ConfigID: 43253, CreateFromVersion: 7}, + appsec.CreateConfigurationCloneRequest{Name: "Test Configuratin", Description: "New configuration test", ContractID: "C-1FRYVV3", GroupID: 64867, Hostnames: []string{"rinaldi.sandbox.akamaideveloper.com", "sujala.sandbox.akamaideveloper.com"}, CreateFrom: struct { + ConfigID int "json:\"configId\"" + Version int "json:\"version\"" + }{ConfigID: 43253, Version: 7}}, ).Return(&cu, nil) + client.On("RemoveConfiguration", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveConfigurationRequest{ConfigID: 43253}, + ).Return(&crd, nil) + useClient(client, func() { resource.Test(t, resource.TestCase{ IsUnitTest: true, @@ -39,7 +51,7 @@ func TestAccAkamaiConfigurationClone_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResConfigurationClone/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_configuration_version_clone.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_configuration_clone.test", "id", "43253"), ), }, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_rename.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_rename.go new file mode 100644 index 000000000..34434fcfc --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_rename.go @@ -0,0 +1,133 @@ +package appsec + +import ( + "context" + "errors" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceConfigurationRename() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceConfigurationRenameUpdate, + ReadContext: resourceConfigurationRenameRead, + UpdateContext: resourceConfigurationRenameUpdate, + DeleteContext: resourceConfigurationRenameDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Required: true, + }, + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + }, + } +} + +func resourceConfigurationRenameUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationRenameUpdate") + + updateConfiguration := appsec.UpdateConfigurationRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateConfiguration.ConfigID = configid + + name, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateConfiguration.Name = name + + description, err := tools.GetStringValue("description", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateConfiguration.Description = description + + _, erru := client.UpdateConfiguration(ctx, updateConfiguration) + if erru != nil { + logger.Errorf("calling 'updateConfiguration': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceConfigurationRenameRead(ctx, d, m) +} + +func resourceConfigurationRenameDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + return schema.NoopContext(nil, d, m) +} + +func resourceConfigurationRenameRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationRenameRead") + + getConfiguration := appsec.GetConfigurationsRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getConfiguration.ConfigID = configid + + configName, err := tools.GetStringValue("name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getConfiguration.Name = configName + + configuration, err := client.GetConfigurations(ctx, getConfiguration) + if err != nil { + logger.Errorf("calling 'getConfiguration': %s", err.Error()) + return diag.FromErr(err) + } + + var configlist string + var configidfound int + configlist = configlist + " ConfigID Name VersionList" + "\n" + + for _, configval := range configuration.Configurations { + + if configval.ID == configid { + d.Set("config_id", configval.ID) + d.Set("latest_version", configval.LatestVersion) + d.Set("staging_version", configval.StagingVersion) + d.Set("production_version", configval.ProductionVersion) + configidfound = configval.ID + } + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "configuration", configuration) + if err == nil { + d.Set("output_text", outputtext) + } + + d.SetId(strconv.Itoa(configidfound)) + + return nil +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_rename_test.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_rename_test.go new file mode 100644 index 000000000..62f441cf1 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_rename_test.go @@ -0,0 +1,58 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiConfigurationRename_res_basic(t *testing.T) { + t.Run("match by Configuration ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateConfigurationResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResConfigurationRename/ConfigurationUpdate.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetConfigurationsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResConfigurationRename/Configuration.json")) + json.Unmarshal([]byte(expectJS), &cr) + + client.On("GetConfigurations", + mock.Anything, // ctx is irrelevant for this test + appsec.GetConfigurationsRequest{ConfigID: 432531, Name: "Akamai Tools New"}, + ).Return(&cr, nil) + + client.On("UpdateConfiguration", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateConfigurationRequest{ConfigID: 432531, Name: "Akamai Tools New", Description: "TF Tools"}, + ).Return(&cu, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResConfigurationRename/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_configuration_rename.test", "id", "432531"), + ), + }, + { + Config: loadFixtureString("testdata/TestResConfigurationRename/update_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_configuration_rename.test", "id", "432531"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_test.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_test.go new file mode 100644 index 000000000..5ad31e245 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_test.go @@ -0,0 +1,76 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiConfiguration_res_basic(t *testing.T) { + t.Run("match by Configuration ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateConfigurationResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResConfiguration/ConfigurationUpdate.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetConfigurationsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResConfiguration/Configuration.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveConfigurationResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResConfiguration/Configuration.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + ccr := appsec.CreateConfigurationResponse{} + expectJSC := compactJSON(loadFixtureBytes("testdata/TestResConfiguration/ConfigurationCreate.json")) + json.Unmarshal([]byte(expectJSC), &ccr) + + client.On("CreateConfiguration", + mock.Anything, // ctx is irrelevant for this test + appsec.CreateConfigurationRequest{Name: "Akamai Tools New", Description: "TF Tools", ContractID: "C-1FRYVV3", GroupID: 64867, Hostnames: []string{"rinaldi.sandbox.akamaideveloper.com", "sujala.sandbox.akamaideveloper.com"}}, + ).Return(&ccr, nil) + + client.On("GetConfigurations", + mock.Anything, // ctx is irrelevant for this test + appsec.GetConfigurationsRequest{ConfigID: 432531, Name: "Akamai Tools New"}, + ).Return(&cr, nil) + + client.On("UpdateConfiguration", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateConfigurationRequest{ConfigID: 432531, Name: "Akamai Tools New", Description: "TF Tools 1"}, + ).Return(&cu, nil) + + client.On("RemoveConfiguration", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveConfigurationRequest{ConfigID: 432531}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResConfiguration/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_configuration.test", "id", "432531"), + ), + }, + { + Config: loadFixtureString("testdata/TestResConfiguration/update_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_configuration.test", "id", "432531"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone.go new file mode 100644 index 000000000..f01a8ef16 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone.go @@ -0,0 +1,133 @@ +package appsec + +import ( + "context" + "errors" + "strconv" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceConfigurationVersionClone() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceConfigurationVersionCloneCreate, + ReadContext: resourceConfigurationVersionCloneRead, + UpdateContext: resourceConfigurationVersionCloneUpdate, + DeleteContext: resourceConfigurationVersionCloneDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "create_from_version": { + Type: schema.TypeInt, + Required: true, + }, + + "rule_update": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "version": { + Type: schema.TypeInt, + Computed: true, + Description: "Version of cloned configuration", + }, + }, + } +} + +func resourceConfigurationVersionCloneCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationVersionCloneCreate") + + createConfigurationVersionClone := appsec.CreateConfigurationVersionCloneRequest{} + + createConfigurationVersionClone.ConfigID = d.Get("config_id").(int) + createConfigurationVersionClone.CreateFromVersion = d.Get("create_from_version").(int) + + ccr, err := client.CreateConfigurationVersionClone(ctx, createConfigurationVersionClone) + if err != nil { + logger.Errorf("calling 'createConfigurationVersionClone': %s", err.Error()) + return diag.FromErr(err) + } + + d.Set("version", ccr.Version) + d.SetId(strconv.Itoa(ccr.Version)) + + return resourceConfigurationVersionCloneRead(ctx, d, m) +} + +func resourceConfigurationVersionCloneRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationVersionCloneRead") + + getConfigurationVersionClone := appsec.GetConfigurationVersionCloneRequest{} + + getConfigurationVersionClone.ConfigID = d.Get("config_id").(int) + //getConfigurationVersionClone.Version = d.Get("create_from_version").(int) + version, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getConfigurationVersionClone.Version = version + + configurationversionclone, err := client.GetConfigurationVersionClone(ctx, getConfigurationVersionClone) + if err != nil { + logger.Errorf("calling 'getConfigurationVersionClone': %s", err.Error()) + return diag.FromErr(err) + } + + //d.SetId(strconv.Itoa(configurationversionclone.ConfigID)) + d.SetId(strconv.Itoa(configurationversionclone.Version)) + return nil +} + +func resourceConfigurationVersionCloneDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceConfigurationVersionCloneRead") + + removeConfigurationVersionClone := appsec.RemoveConfigurationVersionCloneRequest{} + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeConfigurationVersionClone.ConfigID = configid + + version, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + removeConfigurationVersionClone.Version = version + + _, errd := client.RemoveConfigurationVersionClone(ctx, removeConfigurationVersionClone) + if errd != nil { + logger.Errorf("calling 'getConfigurationVersionClone': %s", errd.Error()) + return diag.FromErr(errd) + } + + d.SetId("") + return nil +} + +func resourceConfigurationVersionCloneUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + return schema.NoopContext(nil, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone_test.go b/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone_test.go new file mode 100644 index 000000000..5298731b4 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_configuration_version_clone_test.go @@ -0,0 +1,61 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiConfigurationVersionClone_res_basic(t *testing.T) { + t.Run("match by ConfigurationVersionClone ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.CreateConfigurationVersionCloneResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetConfigurationVersionCloneResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveConfigurationVersionCloneResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("GetConfigurationVersionClone", + mock.Anything, // ctx is irrelevant for this test + appsec.GetConfigurationVersionCloneRequest{ConfigID: 43253, Version: 15}, + ).Return(&cr, nil) + + client.On("CreateConfigurationVersionClone", + mock.Anything, // ctx is irrelevant for this test + appsec.CreateConfigurationVersionCloneRequest{ConfigID: 43253, CreateFromVersion: 7}, + ).Return(&cu, nil) + + client.On("RemoveConfigurationVersionClone", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveConfigurationVersionCloneRequest{ConfigID: 43253, Version: 15}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResConfigurationVersionClone/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_configuration_version_clone.test", "id", "15"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_deny.go b/pkg/providers/appsec/resource_akamai_appsec_custom_deny.go new file mode 100644 index 000000000..81e8a0aa8 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_deny.go @@ -0,0 +1,271 @@ +package appsec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceCustomDeny() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceCustomDenyCreate, + ReadContext: resourceCustomDenyRead, + UpdateContext: resourceCustomDenyUpdate, + DeleteContext: resourceCustomDenyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "custom_deny": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentJsonDiffsGeneric, + }, + "custom_deny_id": { + Type: schema.TypeString, + Computed: true, + Description: "custom_deny_id", + }, + }, + } +} + +func resourceCustomDenyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceCustomDenyCreate") + + createCustomDeny := appsec.CreateCustomDenyRequest{} + + jsonpostpayload := d.Get("custom_deny") + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + + createCustomDeny.JsonPayloadRaw = rawJSON + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createCustomDeny.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createCustomDeny.Version = version + + postresp, errc := client.CreateCustomDeny(ctx, createCustomDeny) + if errc != nil { + logger.Errorf("calling 'createCustomDeny': %s", errc.Error()) + return diag.FromErr(errc) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", createCustomDeny.ConfigID, createCustomDeny.Version, postresp.ID)) + + return resourceCustomDenyRead(ctx, d, m) +} + +func resourceCustomDenyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceCustomDenyUpdate") + + updateCustomDeny := appsec.UpdateCustomDenyRequest{} + + jsonpostpayload := d.Get("custom_deny") + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + + updateCustomDeny.JsonPayloadRaw = rawJSON + + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomDeny.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomDeny.Version = version + + updateCustomDeny.ID = s[2] + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomDeny.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomDeny.Version = version + + updateCustomDeny.ID = d.Id() + } + _, erru := client.UpdateCustomDeny(ctx, updateCustomDeny) + if erru != nil { + logger.Errorf("calling 'updateCustomDeny': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceCustomDenyRead(ctx, d, m) +} + +func resourceCustomDenyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceCustomDenyRemove") + + removeCustomDeny := appsec.RemoveCustomDenyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeCustomDeny.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeCustomDeny.Version = version + + removeCustomDeny.ID = s[2] + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeCustomDeny.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeCustomDeny.Version = version + + removeCustomDeny.ID = d.Id() + } + _, errd := client.RemoveCustomDeny(ctx, removeCustomDeny) + if errd != nil { + logger.Errorf("calling 'removeCustomDeny': %s", errd.Error()) + return diag.FromErr(errd) + } + + d.SetId("") + + return nil +} + +func resourceCustomDenyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceCustomDenyRead") + + getCustomDeny := appsec.GetCustomDenyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomDeny.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomDeny.Version = version + + getCustomDeny.ID = s[2] + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomDeny.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomDeny.Version = version + + getCustomDeny.ID = d.Id() + } + customdeny, err := client.GetCustomDeny(ctx, getCustomDeny) + if err != nil { + logger.Errorf("calling 'getCustomDeny': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "CustomDenyDS", customdeny) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("custom_deny_id", customdeny.ID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("config_id", getCustomDeny.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getCustomDeny.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + jsonBody, err := json.Marshal(customdeny) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("custom_deny", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getCustomDeny.ConfigID, getCustomDeny.Version, customdeny.ID)) + + return nil +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_deny_test.go b/pkg/providers/appsec/resource_akamai_appsec_custom_deny_test.go new file mode 100644 index 000000000..31fcaca1a --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_deny_test.go @@ -0,0 +1,78 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiCustomDeny_res_basic(t *testing.T) { + t.Run("match by CustomDeny ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateCustomDenyResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResCustomDeny/CustomDenyUpdate.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetCustomDenyResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResCustomDeny/CustomDeny.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveCustomDenyResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResCustomDeny/CustomDeny.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("RemoveCustomDeny", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveCustomDenyRequest{ConfigID: 43253, Version: 7, ID: "deny_custom_622918"}, + ).Return(&crd, nil) + + crc := appsec.CreateCustomDenyResponse{} + expectJSC := compactJSON(loadFixtureBytes("testdata/TestResCustomDeny/CustomDenyCreate.json")) + json.Unmarshal([]byte(expectJSC), &crc) + + client.On("GetCustomDeny", + mock.Anything, // ctx is irrelevant for this test + appsec.GetCustomDenyRequest{ConfigID: 43253, Version: 7, ID: "deny_custom_622918"}, + ).Return(&cr, nil) + + client.On("UpdateCustomDeny", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateCustomDenyRequest{ConfigID: 43253, Version: 7, ID: "deny_custom_622918", JsonPayloadRaw: json.RawMessage{0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x50, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x20, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x34, 0x30, 0x33, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x65, 0x77, 0x20, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, + ).Return(&cu, nil) + + client.On("CreateCustomDeny", + mock.Anything, // ctx is irrelevant for this test + appsec.CreateCustomDenyRequest{ConfigID: 43253, Version: 7, JsonPayloadRaw: json.RawMessage{0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x50, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x20, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x34, 0x30, 0x33, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x72, 0x75, 0x65, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x6e, 0x65, 0x77, 0x20, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, + ).Return(&crc, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResCustomDeny/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_custom_deny.test", "id", "43253:7:deny_custom_622918"), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: loadFixtureString("testdata/TestResCustomDeny/update_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_custom_deny.test", "id", "43253:7:deny_custom_622918"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_rule.go b/pkg/providers/appsec/resource_akamai_appsec_custom_rule.go index 5c27c2b46..ba66cc0d1 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_custom_rule.go +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_rule.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -24,15 +25,19 @@ func resourceCustomRule() *schema.Resource { ReadContext: resourceCustomRuleRead, UpdateContext: resourceCustomRuleUpdate, DeleteContext: resourceCustomRuleDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "config_id": { Type: schema.TypeInt, Required: true, }, "custom_rule": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsJSON, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentJsonDiffsGeneric, }, "custom_rule_id": { Type: schema.TypeInt, @@ -55,11 +60,11 @@ func resourceCustomRuleCreate(ctx context.Context, d *schema.ResourceData, m int } createCustomRule.ConfigID = configid - jsonpostpayload := d.Get("custom_rule").(string) + jsonpostpayload := d.Get("custom_rule") - if err := json.Unmarshal([]byte(jsonpostpayload), &createCustomRule); err != nil { - return diag.FromErr(err) - } + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + createCustomRule.JsonPayloadRaw = rawJSON customrule, err := client.CreateCustomRule(ctx, createCustomRule) if err != nil { @@ -71,7 +76,7 @@ func resourceCustomRuleCreate(ctx context.Context, d *schema.ResourceData, m int return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(customrule.ID)) + d.SetId(fmt.Sprintf("%d:%d", createCustomRule.ConfigID, customrule.ID)) return resourceCustomRuleRead(ctx, d, m) } @@ -82,26 +87,42 @@ func resourceCustomRuleUpdate(ctx context.Context, d *schema.ResourceData, m int logger := meta.Log("APPSEC", "resourceCustomRuleUpdate") updateCustomRule := appsec.UpdateCustomRuleRequest{} + jsonpostpayload := d.Get("custom_rule") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRule.ConfigID = configid + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + updateCustomRule.JsonPayloadRaw = rawJSON - ID, errconv := strconv.Atoi(d.Id()) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - if errconv != nil { - return diag.FromErr(errconv) - } - updateCustomRule.ID = ID + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRule.ConfigID = configid - jsonpostpayload := d.Get("custom_rule").(string) + ID, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRule.ID = ID - if err := json.Unmarshal([]byte(jsonpostpayload), &updateCustomRule); err != nil { - return diag.FromErr(err) - } + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRule.ConfigID = configid + + ID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRule.ID = ID + } _, erru := client.UpdateCustomRule(ctx, updateCustomRule) if erru != nil { logger.Errorf("calling 'updateCustomRule': %s", erru.Error()) @@ -117,20 +138,35 @@ func resourceCustomRuleDelete(ctx context.Context, d *schema.ResourceData, m int logger := meta.Log("APPSEC", "resourceCustomRuleRemove") removeCustomRule := appsec.RemoveCustomRuleRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeCustomRule.ConfigID = configid - - ID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeCustomRule.ConfigID = configid + + ID, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeCustomRule.ID = ID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeCustomRule.ConfigID = configid + + ID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + removeCustomRule.ID = ID } - removeCustomRule.ID = ID - _, errd := client.RemoveCustomRule(ctx, removeCustomRule) if errd != nil { logger.Errorf("calling 'removeCustomRule': %s", errd.Error()) @@ -148,30 +184,59 @@ func resourceCustomRuleRead(ctx context.Context, d *schema.ResourceData, m inter logger := meta.Log("APPSEC", "resourceCustomRuleRead") getCustomRule := appsec.GetCustomRuleRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRule.ConfigID = configid + + ID, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRule.ID = ID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRule.ConfigID = configid + + ID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRule.ID = ID + } + customrule, err := client.GetCustomRule(ctx, getCustomRule) + if err != nil { + logger.Errorf("calling 'getCustomRule': %s", err.Error()) return diag.FromErr(err) } - getCustomRule.ConfigID = configid - ID, errconv := strconv.Atoi(d.Id()) + if err := d.Set("custom_rule_id", customrule.ID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - if errconv != nil { - return diag.FromErr(errconv) + if err := d.Set("config_id", getCustomRule.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getCustomRule.ID = ID - customrule, err := client.GetCustomRule(ctx, getCustomRule) + jsonBody, err := json.Marshal(customrule) if err != nil { - logger.Errorf("calling 'getCustomRule': %s", err.Error()) return diag.FromErr(err) } - if err := d.Set("custom_rule_id", customrule.ID); err != nil { + if err := d.Set("custom_rule", string(jsonBody)); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(customrule.ID)) + + d.SetId(fmt.Sprintf("%d:%d", getCustomRule.ConfigID, customrule.ID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action.go b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action.go index 46a40a6f6..4af85e70a 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -57,43 +58,82 @@ func resourceCustomRuleActionRead(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceCustomRuleActionRead") getCustomRuleAction := appsec.GetCustomRuleActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRuleAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRuleAction.Version = version + + policyid := s[2] + getCustomRuleAction.PolicyID = policyid + + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getCustomRuleAction.RuleID = ruleid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("custom_rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getCustomRuleAction.RuleID = ruleid + } + customruleaction, err := client.GetCustomRuleAction(ctx, getCustomRuleAction) + if err != nil { + logger.Errorf("calling 'getCustomRuleAction': %s", err.Error()) return diag.FromErr(err) } - getCustomRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("custom_rule_id", getCustomRuleAction.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getCustomRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("config_id", getCustomRuleAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getCustomRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("custom_rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("version", getCustomRuleAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getCustomRuleAction.RuleID = ruleid - customruleaction, err := client.GetCustomRuleAction(ctx, getCustomRuleAction) - if err != nil { - logger.Errorf("calling 'getCustomRuleAction': %s", err.Error()) - return diag.FromErr(err) + if err := d.Set("security_policy_id", getCustomRuleAction.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - logger.Warnf("calling 'getCustomRuleAction': %s", customruleaction) - if err := d.Set("custom_rule_id", ruleid); err != nil { + if err := d.Set("custom_rule_action", customruleaction.Action); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(ruleid)) + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getCustomRuleAction.ConfigID, getCustomRuleAction.Version, getCustomRuleAction.PolicyID, getCustomRuleAction.RuleID)) return nil } @@ -104,31 +144,55 @@ func resourceCustomRuleActionDelete(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceCustomRuleActionRemove") updateCustomRuleAction := appsec.UpdateCustomRuleActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.Version = version + + policyid := s[2] + updateCustomRuleAction.PolicyID = policyid + + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.RuleID = ruleid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("custom_rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.RuleID = ruleid } - updateCustomRuleAction.Version = version - - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.PolicyID = policyid - - ruleid, err := tools.GetIntValue("custom_rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.RuleID = ruleid - updateCustomRuleAction.Action = "none" _, errd := client.UpdateCustomRuleAction(ctx, updateCustomRuleAction) @@ -148,31 +212,55 @@ func resourceCustomRuleActionUpdate(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceCustomRuleActionUpdate") updateCustomRuleAction := appsec.UpdateCustomRuleActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.Version = version + + policyid := s[2] + updateCustomRuleAction.PolicyID = policyid + + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateCustomRuleAction.RuleID = ruleid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("custom_rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateCustomRuleAction.RuleID = ruleid } - updateCustomRuleAction.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.Version = version - - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.PolicyID = policyid - - ruleid, err := tools.GetIntValue("custom_rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateCustomRuleAction.RuleID = ruleid - customruleaction, err := tools.GetStringValue("custom_rule_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action_test.go b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action_test.go index 349ffb01f..9a59edae0 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_action_test.go @@ -39,8 +39,9 @@ func TestAccAkamaiCustomRuleAction_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResCustomRuleAction/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_custom_rule_action.test", "id", "60036362"), + resource.TestCheckResourceAttr("akamai_appsec_custom_rule_action.test", "id", "43253:7:AAAA_81230:60036362"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_test.go b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_test.go index 8b1fe0b8b..d0aa24747 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_custom_rule_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_custom_rule_test.go @@ -36,84 +36,12 @@ func TestAccAkamaiCustomRule_res_basic(t *testing.T) { client.On("UpdateCustomRule", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateCustomRuleRequest{ConfigID: 43253, ID: 661699, Name: "Rule Test New Updated", Description: "Can I create all conditions?", Version: 0, RuleActivated: false, Tag: []string{"test"}, Conditions: []struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "requestMethodMatch", PositiveMatch: true, Value: []string{"GET", "CONNECT", "TRACE", "PUT", "POST", "OPTIONS", "DELETE", "HEAD"}, ValueWildcard: false, ValueCase: false, NameWildcard: false, Name: []string(nil), NameCase: false}, struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "pathMatch", PositiveMatch: true, Value: []string{"/H", "/Li", "/He"}, ValueWildcard: false, ValueCase: false, NameWildcard: false, Name: []string(nil), NameCase: false}, struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "extensionMatch", PositiveMatch: true, Value: []string{"Li", "He", "H"}, ValueWildcard: true, ValueCase: true, NameWildcard: false, Name: []string(nil), NameCase: false}}}, + appsec.UpdateCustomRuleRequest{ConfigID: 43253, ID: 661699, Version: 0, JsonPayloadRaw: json.RawMessage{0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x75, 0x6c, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x61, 0x6e, 0x20, 0x49, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3f, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x61, 0x67, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x45, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x52, 0x41, 0x43, 0x45, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x55, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x4f, 0x53, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x45, 0x41, 0x44, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x48, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x4c, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x48, 0x65, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4c, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, ).Return(&cu, nil) client.On("CreateCustomRule", mock.Anything, // ctx is irrelevant for this test - appsec.CreateCustomRuleRequest{ConfigID: 43253, Name: "Rule Test New", Description: "Can I create all conditions?", Version: 0, RuleActivated: false, Tag: []string{"test"}, Conditions: []struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "requestMethodMatch", PositiveMatch: true, Value: []string{"GET", "CONNECT", "TRACE", "PUT", "POST", "OPTIONS", "DELETE", "HEAD"}, ValueWildcard: false, ValueCase: false, NameWildcard: false, Name: []string(nil), NameCase: false}, struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "pathMatch", PositiveMatch: true, Value: []string{"/H", "/Li", "/He"}, ValueWildcard: false, ValueCase: false, NameWildcard: false, Name: []string(nil), NameCase: false}, struct { - Type string "json:\"type\"" - PositiveMatch bool "json:\"positiveMatch\"" - Value []string "json:\"value,omitempty\"" - ValueWildcard bool "json:\"valueWildcard,omitempty\"" - ValueCase bool "json:\"valueCase,omitempty\"" - NameWildcard bool "json:\"nameWildcard,omitempty\"" - Name []string "json:\"name,omitempty\"" - NameCase bool "json:\"nameCase,omitempty\"" - }{Type: "extensionMatch", PositiveMatch: true, Value: []string{"Li", "He", "H"}, ValueWildcard: true, ValueCase: true, NameWildcard: false, Name: []string(nil), NameCase: false}}}, + appsec.CreateCustomRuleRequest{ConfigID: 43253, Version: 0, JsonPayloadRaw: json.RawMessage{0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x75, 0x6c, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x77, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x61, 0x6e, 0x20, 0x49, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3f, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x61, 0x67, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x45, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x52, 0x41, 0x43, 0x45, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x55, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x4f, 0x53, 0x54, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x45, 0x41, 0x44, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x48, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x4c, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x48, 0x65, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4c, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x48, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, ).Return(&cc, nil) client.On("RemoveCustomRule", @@ -129,15 +57,17 @@ func TestAccAkamaiCustomRule_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResCustomRule/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_custom_rule.test", "id", "661699"), + resource.TestCheckResourceAttr("akamai_appsec_custom_rule.test", "id", "43253:661699"), ), + ExpectNonEmptyPlan: true, }, { Config: loadFixtureString("testdata/TestResCustomRule/update_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_custom_rule.test", "id", "661699"), + resource.TestCheckResourceAttr("akamai_appsec_custom_rule.test", "id", "43253:661699"), //resource.TestCheckResourceAttr("akamai_appsec_custom_rule.test", "rules", compactJSON(loadFixtureBytes("testdata/TestResCustomRule/custom_rules.json"))), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval.go b/pkg/providers/appsec/resource_akamai_appsec_eval.go index 96096bc31..6639a1080 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_eval.go +++ b/pkg/providers/appsec/resource_akamai_appsec_eval.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -81,31 +82,49 @@ func resourceEvalRead(ctx context.Context, d *schema.ResourceData, m interface{} logger := meta.Log("APPSEC", "resourceEvalRead") getEval := appsec.GetEvalRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEval.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEval.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEval.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEval.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEval.PolicyID = policyid + policyid := s[2] + getEval.PolicyID = policyid - evaloperation, err := tools.GetStringValue("eval_operation", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEval.Eval = evaloperation + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEval.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEval.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEval.PolicyID = policyid + + evaloperation, err := tools.GetStringValue("eval_operation", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEval.Eval = evaloperation + } eval, err := client.GetEval(ctx, getEval) if err != nil { logger.Errorf("calling 'getEval': %s", err.Error()) @@ -138,7 +157,19 @@ func resourceEvalRead(ctx context.Context, d *schema.ResourceData, m interface{} return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getEval.ConfigID)) + if err := d.Set("config_id", getEval.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getEval.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getEval.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getEval.ConfigID, getEval.Version, getEval.PolicyID)) return nil } @@ -150,25 +181,43 @@ func resourceEvalDelete(ctx context.Context, d *schema.ResourceData, m interface logger := meta.Log("APPSEC", "resourceEvalDelete") removeEval := appsec.RemoveEvalRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEval.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEval.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEval.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEval.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEval.PolicyID = policyid + policyid := s[2] + removeEval.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEval.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEval.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEval.PolicyID = policyid + } removeEval.Eval = "STOP" _, erru := client.RemoveEval(ctx, removeEval) @@ -187,25 +236,43 @@ func resourceEvalUpdate(ctx context.Context, d *schema.ResourceData, m interface logger := meta.Log("APPSEC", "resourceEvalUpdate") updateEval := appsec.UpdateEvalRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEval.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEval.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEval.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEval.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEval.PolicyID = policyid + policyid := s[2] + updateEval.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEval.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEval.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEval.PolicyID = policyid + } evaloperation, err := tools.GetStringValue("eval_operation", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_host.go b/pkg/providers/appsec/resource_akamai_appsec_eval_host.go new file mode 100644 index 000000000..1354f951b --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_host.go @@ -0,0 +1,212 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceEvalHost() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceEvalHostUpdate, + ReadContext: resourceEvalHostRead, + UpdateContext: resourceEvalHostUpdate, + DeleteContext: resourceEvalHostDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "hostnames": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func resourceEvalHostRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceEvalHostRead") + + getEvalHost := appsec.GetEvalHostRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalHost.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalHost.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalHost.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalHost.Version = version + } + evalhost, err := client.GetEvalHost(ctx, getEvalHost) + if err != nil { + logger.Errorf("calling 'getEvalHost': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "evalHostDS", evalhost) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getEvalHost.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getEvalHost.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getEvalHost.ConfigID, getEvalHost.Version)) + + return nil +} + +func resourceEvalHostDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceEvalHostRemove") + + removeEvalHost := appsec.RemoveEvalHostRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalHost.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalHost.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalHost.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalHost.Version = version + } + hn := make([]string, 0, 1) + + removeEvalHost.Hostnames = hn + + _, erru := client.RemoveEvalHost(ctx, removeEvalHost) + if erru != nil { + logger.Errorf("calling 'updateEvalHost': %s", erru.Error()) + return diag.FromErr(erru) + } + d.SetId("") + return nil +} + +func resourceEvalHostUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceEvalHostUpdate") + + updateEvalHost := appsec.UpdateEvalHostRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalHost.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalHost.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalHost.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalHost.Version = version + } + hostnames := d.Get("hostnames").([]interface{}) + hn := make([]string, 0, len(hostnames)) + + for _, h := range hostnames { + hn = append(hn, h.(string)) + + } + updateEvalHost.Hostnames = hn + + _, erru := client.UpdateEvalHost(ctx, updateEvalHost) + if erru != nil { + logger.Errorf("calling 'updateEvalHost': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceEvalHostRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_host_test.go b/pkg/providers/appsec/resource_akamai_appsec_eval_host_test.go new file mode 100644 index 000000000..62efd1956 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_host_test.go @@ -0,0 +1,61 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiEvalHost_res_basic(t *testing.T) { + t.Run("match by EvalHost ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateEvalHostResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResEvalHost/EvalHost.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetEvalHostResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResEvalHost/EvalHost.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveEvalHostResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResEvalHost/EvalHost.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("GetEvalHost", + mock.Anything, // ctx is irrelevant for this test + appsec.GetEvalHostRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateEvalHost", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateEvalHostRequest{ConfigID: 43253, Version: 7, Hostnames: []string{"example.com"}}, + ).Return(&cu, nil) + + client.On("RemoveEvalHost", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveEvalHostRequest{ConfigID: 43253, Version: 7, Hostnames: []string{}}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResEvalHost/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_eval_hostnames.test", "id", "43253:7"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host.go b/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host.go new file mode 100644 index 000000000..a5ef6d941 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host.go @@ -0,0 +1,169 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceEvalProtectHost() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceEvalProtectHostUpdate, + ReadContext: resourceEvalProtectHostRead, + UpdateContext: resourceEvalProtectHostUpdate, + DeleteContext: resourceEvalProtectHostDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "hostnames": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func resourceEvalProtectHostRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceEvalProtectHostRead") + + getEvalProtectHost := appsec.GetEvalProtectHostRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalProtectHost.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalProtectHost.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalProtectHost.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalProtectHost.Version = version + } + evalprotecthost, err := client.GetEvalProtectHost(ctx, getEvalProtectHost) + if err != nil { + logger.Errorf("calling 'getEvalProtectHost': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "evalProtectHostDS", evalprotecthost) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getEvalProtectHost.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getEvalProtectHost.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getEvalProtectHost.ConfigID, getEvalProtectHost.Version)) + + return nil +} + +func resourceEvalProtectHostDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + return schema.NoopContext(nil, d, m) +} + +func resourceEvalProtectHostUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceEvalProtectHostUpdate") + + updateEvalProtectHost := appsec.UpdateEvalProtectHostRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalProtectHost.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalProtectHost.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalProtectHost.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalProtectHost.Version = version + } + hostnames := d.Get("hostnames").([]interface{}) + hn := make([]string, 0, len(hostnames)) + + for _, h := range hostnames { + hn = append(hn, h.(string)) + + } + updateEvalProtectHost.Hostnames = hn + + _, erru := client.UpdateEvalProtectHost(ctx, updateEvalProtectHost) + if erru != nil { + logger.Errorf("calling 'updateEvalProtectHost': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceEvalProtectHostRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host_test.go b/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host_test.go new file mode 100644 index 000000000..1cb13757b --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_protect_host_test.go @@ -0,0 +1,52 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiEvalProtectHost_res_basic(t *testing.T) { + t.Run("match by EvalProtectHost ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateEvalProtectHostResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResEvalProtectHost/EvalProtectHost.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetEvalProtectHostResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResEvalProtectHost/EvalProtectHost.json")) + json.Unmarshal([]byte(expectJS), &cr) + + client.On("GetEvalProtectHost", + mock.Anything, // ctx is irrelevant for this test + appsec.GetEvalProtectHostRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateEvalProtectHost", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateEvalProtectHostRequest{ConfigID: 43253, Version: 7, Hostnames: []string{"example.com"}}, + ).Return(&cu, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResEvalProtectHost/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_eval_protect_host.test", "id", "43253:7"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action.go b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action.go index b0d78ffb8..d052fb6f7 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -47,11 +48,6 @@ func resourceEvalRuleAction() *schema.Resource { Type: schema.TypeInt, Required: true, }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -62,47 +58,84 @@ func resourceEvalRuleActionRead(ctx context.Context, d *schema.ResourceData, m i logger := meta.Log("APPSEC", "resourceEvalRuleActionRead") getEvalRuleAction := appsec.GetEvalRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleAction.Version = version + + policyid := s[2] + getEvalRuleAction.PolicyID = policyid + + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleAction.RuleID = ruleid + } + evalruleaction, err := client.GetEvalRuleAction(ctx, getEvalRuleAction) + if err != nil { + logger.Warnf("calling 'getEvalRuleAction': %s", err.Error()) } - getEvalRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("rule_id", getEvalRuleAction.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getEvalRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("config_id", getEvalRuleAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getEvalRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("version", getEvalRuleAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getEvalRuleAction.RuleID = ruleid - evalruleaction, err := client.GetEvalRuleAction(ctx, getEvalRuleAction) - if err != nil { - logger.Warnf("calling 'getEvalRuleAction': %s", err.Error()) + if err := d.Set("security_policy_id", getEvalRuleAction.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - ots := OutputTemplates{} - InitTemplates(ots) + if err := d.Set("rule_id", getEvalRuleAction.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "EvalRuleAction", evalruleaction) - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("rule_action", evalruleaction.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getEvalRuleAction.ConfigID)) + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getEvalRuleAction.ConfigID, getEvalRuleAction.Version, getEvalRuleAction.PolicyID, getEvalRuleAction.RuleID)) return nil } @@ -114,31 +147,54 @@ func resourceEvalRuleActionDelete(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceEvalRuleActionRemove") removeEvalRuleAction := appsec.UpdateEvalRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleAction.PolicyID = policyid + policyid := s[2] + removeEvalRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleAction.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleAction.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleAction.RuleID = ruleid + } removeEvalRuleAction.Action = "none" _, erru := client.UpdateEvalRuleAction(ctx, removeEvalRuleAction) @@ -155,35 +211,57 @@ func resourceEvalRuleActionUpdate(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceEvalRuleActionUpdate") updateEvalRuleAction := appsec.UpdateEvalRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleAction.PolicyID = policyid + policyid := s[2] + updateEvalRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleAction.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleAction.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleAction.RuleID = ruleid + } ruleaction, err := tools.GetStringValue("rule_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) - return diag.FromErr(err) } updateEvalRuleAction.Action = ruleaction diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action_test.go b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action_test.go index 26a3fbb3f..7f0fcb0b0 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_action_test.go @@ -39,8 +39,9 @@ func TestAccAkamaiEvalRuleAction_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResEvalRuleAction/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_eval_rule_action.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_eval_rule_action.test", "id", "43253:7:AAAA_81230:699989"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception.go b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception.go index e2d439111..7e7698133 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception.go +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -50,11 +51,6 @@ func resourceEvalRuleConditionException() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: suppressEquivalentJSONDiffsConditionException, }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -65,47 +61,85 @@ func resourceEvalRuleConditionExceptionRead(ctx context.Context, d *schema.Resou logger := meta.Log("APPSEC", "resourceEvalRuleConditionExceptionRead") getEvalRuleConditionException := appsec.GetEvalRuleConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEvalRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEvalRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEvalRuleConditionException.PolicyID = policyid + policyid := s[2] + getEvalRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getEvalRuleConditionException.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getEvalRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleConditionException.PolicyID = policyid + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getEvalRuleConditionException.RuleID = ruleid + } evalruleconditionexception, err := client.GetEvalRuleConditionException(ctx, getEvalRuleConditionException) if err != nil { logger.Warnf("calling 'getEvalRuleConditionException': %s", err.Error()) } - ots := OutputTemplates{} - InitTemplates(ots) + jsonBody, err := json.Marshal(evalruleconditionexception) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("condition_exception", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "EvalRuleConditionExceptions", evalruleconditionexception) + if err := d.Set("rule_id", getEvalRuleConditionException.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("config_id", getEvalRuleConditionException.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } + if err := d.Set("version", getEvalRuleConditionException.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getEvalRuleConditionException.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getEvalRuleConditionException.ConfigID, getEvalRuleConditionException.Version, getEvalRuleConditionException.PolicyID, getEvalRuleConditionException.RuleID)) + d.SetId(strconv.Itoa(getEvalRuleConditionException.ConfigID)) return nil @@ -118,32 +152,54 @@ func resourceEvalRuleConditionExceptionDelete(ctx context.Context, d *schema.Res logger := meta.Log("APPSEC", "resourceEvalRuleConditionExceptionRemove") removeEvalRuleConditionException := appsec.RemoveEvalRuleConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleConditionException.PolicyID = policyid + policyid := s[2] + removeEvalRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeEvalRuleConditionException.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeEvalRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleConditionException.ConfigID = configid - logger.Errorf("calling 'RemoveEvalRuleConditionException': %v", removeEvalRuleConditionException) + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleConditionException.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeEvalRuleConditionException.RuleID = ruleid + } _, errd := client.RemoveEvalRuleConditionException(ctx, removeEvalRuleConditionException) if errd != nil { @@ -165,32 +221,57 @@ func resourceEvalRuleConditionExceptionUpdate(ctx context.Context, d *schema.Res jsonpostpayload := d.Get("condition_exception") - json.Unmarshal([]byte(jsonpostpayload.(string)), &updateEvalRuleConditionException) + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + updateEvalRuleConditionException.JsonPayloadRaw = rawJSON + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleConditionException.PolicyID = policyid + policyid := s[2] + updateEvalRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateEvalRuleConditionException.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateEvalRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleConditionException.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleConditionException.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateEvalRuleConditionException.RuleID = ruleid + } _, erru := client.UpdateEvalRuleConditionException(ctx, updateEvalRuleConditionException) if erru != nil { logger.Warnf("calling 'updateEvalRuleConditionException': %s", erru.Error()) diff --git a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception_test.go b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception_test.go index ec3bdc4e3..2b2bb4411 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_eval_rule_condition_exception_test.go @@ -37,21 +37,7 @@ func TestAccAkamaiEvalRuleConditionException_res_basic(t *testing.T) { client.On("UpdateEvalRuleConditionException", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateEvalRuleConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", RuleID: 12345, Conditions: []struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{}, Exception: struct { - HeaderCookieOrParamValues []string "json:\"headerCookieOrParamValues\"" - SpecificHeaderCookieOrParamNames []struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - } "json:\"specificHeaderCookieOrParamNames\"" - }{HeaderCookieOrParamValues: []string{"abc"}, SpecificHeaderCookieOrParamNames: []struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }(nil)}}, + appsec.UpdateEvalRuleConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", RuleID: 12345, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x62, 0x63, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x2a, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x43, 0x4f, 0x4f, 0x4b, 0x49, 0x45, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x7d, 0xa}}, ).Return(&cu, nil) useClient(client, func() { @@ -64,6 +50,7 @@ func TestAccAkamaiEvalRuleConditionException_res_basic(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("akamai_appsec_eval_rule_condition_exception.test", "id", "43253"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_ip_geo.go b/pkg/providers/appsec/resource_akamai_appsec_ip_geo.go index 405563f1d..8da46643e 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_ip_geo.go +++ b/pkg/providers/appsec/resource_akamai_appsec_ip_geo.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -77,25 +78,43 @@ func resourceIPGeoRead(ctx context.Context, d *schema.ResourceData, m interface{ logger := meta.Log("APPSEC", "resourceIPGeoRead") getIPGeo := appsec.GetIPGeoRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getIPGeo.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getIPGeo.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getIPGeo.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getIPGeo.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getIPGeo.PolicyID = policyid + policyid := s[2] + getIPGeo.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getIPGeo.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getIPGeo.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getIPGeo.PolicyID = policyid + } ipgeo, err := client.GetIPGeo(ctx, getIPGeo) if err != nil { logger.Errorf("calling 'getIPGeo': %s", err.Error()) @@ -112,7 +131,43 @@ func resourceIPGeoRead(ctx context.Context, d *schema.ResourceData, m interface{ } } - d.SetId(strconv.Itoa(getIPGeo.ConfigID)) + if err := d.Set("config_id", getIPGeo.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getIPGeo.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getIPGeo.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if ipgeo.Block == "blockAllTrafficExceptAllowedIPs" { + if err := d.Set("mode", Allow); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } + + if ipgeo.Block == "blockSpecificIPGeo" { + if err := d.Set("mode", Block); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } + + if err := d.Set("geo_network_lists", ipgeo.GeoControls.BlockedIPNetworkLists.NetworkList); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("ip_network_lists", ipgeo.IPControls.BlockedIPNetworkLists.NetworkList); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("exception_ip_network_lists", ipgeo.IPControls.AllowedIPNetworkLists.NetworkList); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getIPGeo.ConfigID, getIPGeo.Version, getIPGeo.PolicyID)) return nil } @@ -124,25 +179,43 @@ func resourceIPGeoDelete(ctx context.Context, d *schema.ResourceData, m interfac logger := meta.Log("APPSEC", "resourceIPGeoDelete") updatePolicyProtections := appsec.UpdateNetworkLayerProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.PolicyID = policyid + policyid := s[2] + updatePolicyProtections.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.PolicyID = policyid + } updatePolicyProtections.ApplyNetworkLayerControls = false logger.Errorf("calling 'resourceIPGeoDelete': %v", updatePolicyProtections) @@ -161,25 +234,43 @@ func resourceIPGeoUpdate(ctx context.Context, d *schema.ResourceData, m interfac logger := meta.Log("APPSEC", "resourceIPGeoUpdate") updateIPGeo := appsec.UpdateIPGeoRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateIPGeo.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateIPGeo.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateIPGeo.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateIPGeo.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateIPGeo.PolicyID = policyid + policyid := s[2] + updateIPGeo.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateIPGeo.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateIPGeo.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateIPGeo.PolicyID = policyid + } mode, err := tools.GetStringValue("mode", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_match_target.go b/pkg/providers/appsec/resource_akamai_appsec_match_target.go index 064948d98..f3aeeebc9 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_match_target.go +++ b/pkg/providers/appsec/resource_akamai_appsec_match_target.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -24,6 +25,9 @@ func resourceMatchTarget() *schema.Resource { ReadContext: resourceMatchTargetRead, UpdateContext: resourceMatchTargetUpdate, DeleteContext: resourceMatchTargetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "config_id": { Type: schema.TypeInt, @@ -56,9 +60,22 @@ func resourceMatchTargetCreate(ctx context.Context, d *schema.ResourceData, m in jsonpostpayload := d.Get("match_target") - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &createMatchTarget); err != nil { + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + + createMatchTarget.JsonPayloadRaw = rawJSON + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createMatchTarget.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) } + createMatchTarget.ConfigVersion = version postresp, err := client.CreateMatchTarget(ctx, createMatchTarget) if err != nil { @@ -93,32 +110,55 @@ func resourceMatchTargetUpdate(ctx context.Context, d *schema.ResourceData, m in jsonpostpayload := d.Get("match_target") - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &updateMatchTarget); err != nil { - return diag.FromErr(err) - } + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) - targetID, errconv := strconv.Atoi(d.Id()) + updateMatchTarget.JsonPayloadRaw = rawJSON - if errconv != nil { - return diag.FromErr(errconv) - } - updateMatchTarget.TargetID = targetID + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - jsonBody, err := json.Marshal(updateMatchTarget) - if err != nil { - return diag.FromErr(err) - } + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateMatchTarget.ConfigID = configid - if err := d.Set("match_target", string(jsonBody)); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateMatchTarget.ConfigVersion = version + + targetID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateMatchTarget.TargetID = targetID + + } else { + targetID, errconv := strconv.Atoi(d.Id()) + if errconv != nil { + return diag.FromErr(errconv) + } + updateMatchTarget.TargetID = targetID + + jsonBody, err := json.Marshal(updateMatchTarget) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("match_target", string(jsonBody)); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + } resp, err := client.UpdateMatchTarget(ctx, updateMatchTarget) if err != nil { logger.Errorf("calling 'updateMatchTarget': %s", err.Error()) return diag.FromErr(err) } - jsonBody, err = json.Marshal(resp) + jsonBody, err := json.Marshal(resp) if err != nil { return diag.FromErr(err) } @@ -136,26 +176,47 @@ func resourceMatchTargetDelete(ctx context.Context, d *schema.ResourceData, m in logger := meta.Log("APPSEC", "resourceMatchTargetRemove") removeMatchTarget := appsec.RemoveMatchTargetRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeMatchTarget.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeMatchTarget.ConfigVersion = version + + targetID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeMatchTarget.TargetID = targetID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeMatchTarget.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeMatchTarget.ConfigVersion = version + + targetID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + removeMatchTarget.TargetID = targetID } - removeMatchTarget.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeMatchTarget.ConfigVersion = version - - targetID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) - } - removeMatchTarget.TargetID = targetID - _, errd := client.RemoveMatchTarget(ctx, removeMatchTarget) if errd != nil { logger.Errorf("calling 'removeMatchTarget': %s", errd.Error()) @@ -173,26 +234,47 @@ func resourceMatchTargetRead(ctx context.Context, d *schema.ResourceData, m inte logger := meta.Log("APPSEC", "resourceMatchTargetRead") getMatchTarget := appsec.GetMatchTargetRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getMatchTarget.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getMatchTarget.ConfigVersion = version - - targetID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getMatchTarget.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getMatchTarget.ConfigVersion = version + + targetID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + getMatchTarget.TargetID = targetID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getMatchTarget.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getMatchTarget.ConfigVersion = version + + targetID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getMatchTarget.TargetID = targetID } - getMatchTarget.TargetID = targetID - matchtarget, err := client.GetMatchTarget(ctx, getMatchTarget) if err != nil { logger.Errorf("calling 'getMatchTarget': %s", err.Error()) @@ -203,7 +285,7 @@ func resourceMatchTargetRead(ctx context.Context, d *schema.ResourceData, m inte if err != nil { return diag.FromErr(err) } - + logger.Warnf("calling 'getMatchTarget': JSON %s", string(jsonBody)) if err := d.Set("match_target", string(jsonBody)); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } @@ -211,8 +293,15 @@ func resourceMatchTargetRead(ctx context.Context, d *schema.ResourceData, m inte if err := d.Set("match_target_id", matchtarget.TargetID); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } + if err := d.Set("config_id", getMatchTarget.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getMatchTarget.ConfigVersion); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - d.SetId(strconv.Itoa(matchtarget.TargetID)) + d.SetId(fmt.Sprintf("%d:%d:%d", getMatchTarget.ConfigID, getMatchTarget.ConfigVersion, matchtarget.TargetID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_match_target_test.go b/pkg/providers/appsec/resource_akamai_appsec_match_target_test.go index c45c4836f..238912bb8 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_match_target_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_match_target_test.go @@ -15,7 +15,6 @@ func TestAccAkamaiMatchTarget_res_basic(t *testing.T) { cu := appsec.UpdateMatchTargetResponse{} expectJSU := compactJSON(loadFixtureBytes("testdata/TestResMatchTarget/MatchTargetUpdated.json")) - //expectJSU := compactJSON(loadFixtureBytes("testdata/TestResMatchTarget/MatchTarget.json")) json.Unmarshal([]byte(expectJSU), &cu) cr := appsec.GetMatchTargetResponse{} @@ -24,7 +23,6 @@ func TestAccAkamaiMatchTarget_res_basic(t *testing.T) { crmt := appsec.CreateMatchTargetResponse{} expectJSMT := compactJSON(loadFixtureBytes("testdata/TestResMatchTarget/MatchTargetCreated.json")) - //expectJSMT := compactJSON(loadFixtureBytes("testdata/TestResMatchTarget/MatchTarget.json")) json.Unmarshal([]byte(expectJSMT), &crmt) rmmt := appsec.RemoveMatchTargetResponse{} @@ -38,36 +36,12 @@ func TestAccAkamaiMatchTarget_res_basic(t *testing.T) { client.On("CreateMatchTarget", mock.Anything, // ctx is irrelevant for this test - appsec.CreateMatchTargetRequest{Type: "website", ConfigID: 43253, ConfigVersion: 15, DefaultFile: "NO_MATCH", EffectiveSecurityControls: struct { - ApplyApplicationLayerControls bool "json:\"applyApplicationLayerControls\"" - ApplyBotmanControls bool "json:\"applyBotmanControls\"" - ApplyNetworkLayerControls bool "json:\"applyNetworkLayerControls\"" - ApplyRateControls bool "json:\"applyRateControls\"" - ApplyReputationControls bool "json:\"applyReputationControls\"" - ApplySlowPostControls bool "json:\"applySlowPostControls\"" - }{ApplyApplicationLayerControls: false, ApplyBotmanControls: false, ApplyNetworkLayerControls: false, ApplyRateControls: false, ApplyReputationControls: false, ApplySlowPostControls: false}, FileExtensions: []string{"carb", "pct", "pdf", "swf", "cct", "jpeg", "js", "wmls", "hdml", "pws"}, FilePaths: []string{"/cache/aaabbc*"}, Hostnames: []string{"m.example.com", "www.example.net", "example.com"}, IsNegativeFileExtensionMatch: false, IsNegativePathMatch: false, SecurityPolicy: struct { - PolicyID string "json:\"policyId\"" - }{PolicyID: "AAAA_81230"}, Sequence: 1, BypassNetworkLists: []struct { - Name string "json:\"name\"" - ID string "json:\"id\"" - }(nil)}, + appsec.CreateMatchTargetRequest{Type: "", ConfigID: 43253, ConfigVersion: 15, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x22, 0x3a, 0x20, 0x34, 0x33, 0x32, 0x35, 0x33, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x20, 0x31, 0x35, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x4e, 0x4f, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x6f, 0x74, 0x6d, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x6c, 0x6f, 0x77, 0x50, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x72, 0x62, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x63, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x64, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x77, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x63, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6a, 0x70, 0x65, 0x67, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6a, 0x73, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x6d, 0x6c, 0x73, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x64, 0x6d, 0x6c, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x77, 0x73, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x61, 0x61, 0x61, 0x62, 0x62, 0x63, 0x2a, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x4e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x4e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x41, 0x41, 0x41, 0x5f, 0x38, 0x31, 0x32, 0x33, 0x30, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x20, 0x31, 0xa, 0x7d, 0xa}}, ).Return(&crmt, nil) client.On("UpdateMatchTarget", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateMatchTargetRequest{Type: "website", ConfigID: 43253, ConfigVersion: 15, TargetID: 3008967, DefaultFile: "NO_MATCH", EffectiveSecurityControls: struct { - ApplyApplicationLayerControls bool "json:\"applyApplicationLayerControls\"" - ApplyBotmanControls bool "json:\"applyBotmanControls\"" - ApplyNetworkLayerControls bool "json:\"applyNetworkLayerControls\"" - ApplyRateControls bool "json:\"applyRateControls\"" - ApplyReputationControls bool "json:\"applyReputationControls\"" - ApplySlowPostControls bool "json:\"applySlowPostControls\"" - }{ApplyApplicationLayerControls: false, ApplyBotmanControls: false, ApplyNetworkLayerControls: false, ApplyRateControls: false, ApplyReputationControls: false, ApplySlowPostControls: false}, FileExtensions: []string{"carb", "pct", "pdf", "swf", "cct", "jpeg", "js", "wmls", "hdml", "pws"}, FilePaths: []string{"/cache/aaabbc*"}, Hostnames: []string{"m1.example.com", "www.example.net", "example.com"}, IsNegativeFileExtensionMatch: false, IsNegativePathMatch: false, SecurityPolicy: struct { - PolicyID string "json:\"policyId\"" - }{PolicyID: "AAAA_81230"}, Sequence: 1, BypassNetworkLists: []struct { - Name string "json:\"name\"" - ID string "json:\"id\"" - }(nil)}, + appsec.UpdateMatchTargetRequest{ConfigID: 43253, ConfigVersion: 15, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x22, 0x3a, 0x20, 0x34, 0x33, 0x32, 0x35, 0x33, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x20, 0x31, 0x35, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x4e, 0x4f, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x6f, 0x74, 0x6d, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x6c, 0x6f, 0x77, 0x50, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x72, 0x62, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x63, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x64, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x77, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x63, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6a, 0x70, 0x65, 0x67, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6a, 0x73, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x6d, 0x6c, 0x73, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x64, 0x6d, 0x6c, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x77, 0x73, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x61, 0x61, 0x61, 0x62, 0x62, 0x63, 0x2a, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x31, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x4e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x73, 0x4e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x41, 0x41, 0x41, 0x5f, 0x38, 0x31, 0x32, 0x33, 0x30, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x20, 0x31, 0xa, 0x7d, 0xa}, TargetID: 3008967}, ).Return(&cu, nil) client.On("RemoveMatchTarget", @@ -83,15 +57,14 @@ func TestAccAkamaiMatchTarget_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResMatchTarget/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_match_target.test", "id", "3008967"), //3008967 + resource.TestCheckResourceAttr("akamai_appsec_match_target.test", "id", "43253:15:3008967"), ), ExpectNonEmptyPlan: true, }, { Config: loadFixtureString("testdata/TestResMatchTarget/update_by_id.tf"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_match_target.test", "id", "3008967"), - //resource.TestCheckResourceAttr("akamai_appsec_match_target.test", "is_negative_file_extension_match", "false"), + resource.TestCheckResourceAttr("akamai_appsec_match_target.test", "id", "43253:15:3008967"), ), ExpectNonEmptyPlan: true, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_penalty_box.go b/pkg/providers/appsec/resource_akamai_appsec_penalty_box.go index 0a72f81dc..9c013cff2 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_penalty_box.go +++ b/pkg/providers/appsec/resource_akamai_appsec_penalty_box.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -52,11 +53,6 @@ func resourcePenaltyBox() *schema.Resource { None, }, false), }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -67,42 +63,70 @@ func resourcePenaltyBoxRead(ctx context.Context, d *schema.ResourceData, m inter logger := meta.Log("APPSEC", "resourcePenaltyBoxRead") getPenaltyBox := appsec.GetPenaltyBoxRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPenaltyBox.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPenaltyBox.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPenaltyBox.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPenaltyBox.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPenaltyBox.PolicyID = policyid + policyid := s[2] + getPenaltyBox.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPenaltyBox.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPenaltyBox.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPenaltyBox.PolicyID = policyid + } penaltybox, err := client.GetPenaltyBox(ctx, getPenaltyBox) if err != nil { logger.Errorf("calling 'getPenaltyBox': %s", err.Error()) return diag.FromErr(err) } - ots := OutputTemplates{} - InitTemplates(ots) + if err := d.Set("config_id", getPenaltyBox.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getPenaltyBox.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "penaltyBoxesDS", penaltybox) - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("security_policy_id", getPenaltyBox.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("penalty_box_protection", penaltybox.PenaltyBoxProtection); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("penalty_box_action", penaltybox.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getPenaltyBox.ConfigID)) + d.SetId(fmt.Sprintf("%d:%d:%s", getPenaltyBox.ConfigID, getPenaltyBox.Version, getPenaltyBox.PolicyID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_rate_policy.go b/pkg/providers/appsec/resource_akamai_appsec_rate_policy.go index a0f78c7e2..4f586aec8 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rate_policy.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rate_policy.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -25,6 +26,9 @@ func resourceRatePolicy() *schema.Resource { ReadContext: resourceRatePolicyRead, UpdateContext: resourceRatePolicyUpdate, DeleteContext: resourceRatePolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "config_id": { Type: schema.TypeInt, @@ -55,10 +59,10 @@ func resourceRatePolicyCreate(ctx context.Context, d *schema.ResourceData, m int createRatePolicy := appsec.CreateRatePolicyRequest{} jsonpostpayload := d.Get("rate_policy") + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &createRatePolicy); err != nil { - return diag.FromErr(err) - } + createRatePolicy.JsonPayloadRaw = rawJSON configid, err := tools.GetIntValue("config_id", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { @@ -78,7 +82,7 @@ func resourceRatePolicyCreate(ctx context.Context, d *schema.ResourceData, m int return diag.FromErr(err) } - d.SetId(strconv.Itoa(ratepolicy.ID)) + d.SetId(fmt.Sprintf("%d:%d:%d", createRatePolicy.ConfigID, createRatePolicy.ConfigVersion, ratepolicy.ID)) return resourceRatePolicyRead(ctx, d, meta) } @@ -91,30 +95,51 @@ func resourceRatePolicyUpdate(ctx context.Context, d *schema.ResourceData, m int updateRatePolicy := appsec.UpdateRatePolicyRequest{} jsonpostpayload := d.Get("rate_policy") - - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &updateRatePolicy); err != nil { - return diag.FromErr(err) - } - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + + updateRatePolicy.JsonPayloadRaw = rawJSON + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicy.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicy.RatePolicyID = ratePolicyID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicy.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicy.RatePolicyID = ratePolicyID } - updateRatePolicy.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicy.ConfigVersion = version - - ratePolicyID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) - } - updateRatePolicy.RatePolicyID = ratePolicyID - _, erru := client.UpdateRatePolicy(ctx, updateRatePolicy) if erru != nil { logger.Warnf("calling 'updateRatePolicyAction': %s", erru.Error()) @@ -130,26 +155,47 @@ func resourceRatePolicyDelete(ctx context.Context, d *schema.ResourceData, m int logger := meta.Log("APPSEC", "resourceRatePolicyDelete") deleteRatePolicy := appsec.RemoveRatePolicyRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - deleteRatePolicy.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - deleteRatePolicy.ConfigVersion = version - - ratePolicyID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + deleteRatePolicy.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + deleteRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + deleteRatePolicy.RatePolicyID = ratePolicyID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + deleteRatePolicy.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + deleteRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + deleteRatePolicy.RatePolicyID = ratePolicyID } - deleteRatePolicy.RatePolicyID = ratePolicyID - _, errd := client.RemoveRatePolicy(ctx, deleteRatePolicy) if errd != nil { logger.Warnf("calling 'removeRatePolicyAction': %s", errd.Error()) @@ -167,26 +213,47 @@ func resourceRatePolicyRead(ctx context.Context, d *schema.ResourceData, m inter logger := meta.Log("APPSEC", "resourceRatePolicyRead") getRatePolicy := appsec.GetRatePolicyRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRatePolicy.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicy.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicy.RatePolicyID = ratePolicyID + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicy.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicy.ConfigVersion = version + + ratePolicyID, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicy.RatePolicyID = ratePolicyID } - getRatePolicy.ConfigVersion = version - - ratePolicyID, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) - } - getRatePolicy.RatePolicyID = ratePolicyID - ratepolicy, errd := client.GetRatePolicy(ctx, getRatePolicy) if errd != nil { logger.Warnf("calling 'getRatePolicyAction': %s", errd.Error()) @@ -197,7 +264,18 @@ func resourceRatePolicyRead(ctx context.Context, d *schema.ResourceData, m inter return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(ratepolicy.ID)) + if err := d.Set("config_id", getRatePolicy.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getRatePolicy.ConfigVersion); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("rate_policy_id", ratepolicy.ID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d:%d", getRatePolicy.ConfigID, getRatePolicy.ConfigVersion, ratepolicy.ID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_rate_policy_action.go b/pkg/providers/appsec/resource_akamai_appsec_rate_policy_action.go index 3da8ea4d2..98ea1b054 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rate_policy_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rate_policy_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -62,31 +63,54 @@ func resourceRatePolicyActionRead(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceRatePolicyActionRead") getRatePolicyAction := appsec.GetRatePolicyActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRatePolicyAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicyAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRatePolicyAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicyAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRatePolicyAction.PolicyID = policyid + policyid := s[2] + getRatePolicyAction.PolicyID = policyid - ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRatePolicyAction.ID = ratepolicyid + ratepolicyid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRatePolicyAction.ID = ratepolicyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicyAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicyAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicyAction.PolicyID = policyid + ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRatePolicyAction.ID = ratepolicyid + } ratepolicyaction, err := client.GetRatePolicyAction(ctx, getRatePolicyAction) if err != nil { logger.Errorf("calling 'getRatePolicyAction': %s", err.Error()) @@ -106,7 +130,20 @@ func resourceRatePolicyActionRead(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(configval.ID)) + if err := d.Set("config_id", getRatePolicyAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getRatePolicyAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getRatePolicyAction.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getRatePolicyAction.ConfigID, getRatePolicyAction.Version, getRatePolicyAction.PolicyID, getRatePolicyAction.ID)) + } } @@ -119,31 +156,54 @@ func resourceRatePolicyActionDelete(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceRatePolicyActionRemove") updateRatePolicyAction := appsec.UpdateRatePolicyActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.PolicyID = policyid + policyid := s[2] + updateRatePolicyAction.PolicyID = policyid - ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.RatePolicyID = ratepolicyid + ratepolicyid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.RatePolicyID = ratepolicyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.PolicyID = policyid + + ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.RatePolicyID = ratepolicyid + } updateRatePolicyAction.Ipv4Action = "none" updateRatePolicyAction.Ipv6Action = "none" @@ -164,31 +224,54 @@ func resourceRatePolicyActionUpdate(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceRatePolicyActionUpdate") updateRatePolicyAction := appsec.UpdateRatePolicyActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.PolicyID = policyid + policyid := s[2] + updateRatePolicyAction.PolicyID = policyid - ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRatePolicyAction.RatePolicyID = ratepolicyid + ratepolicyid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRatePolicyAction.RatePolicyID = ratepolicyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.PolicyID = policyid + + ratepolicyid, err := tools.GetIntValue("rate_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRatePolicyAction.RatePolicyID = ratepolicyid + } ipv4action, err := tools.GetStringValue("ipv4_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_rate_policy_test.go b/pkg/providers/appsec/resource_akamai_appsec_rate_policy_test.go index afd8d63d3..6fc913891 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rate_policy_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rate_policy_test.go @@ -36,68 +36,12 @@ func TestAccAkamaiRatePolicy_res_basic(t *testing.T) { client.On("UpdateRatePolicy", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateRatePolicyRequest{ConfigID: 43253, ConfigVersion: 7, RatePolicyID: 134644, MatchType: "path", Type: "WAF", Name: "Test_Paths 3", Description: "AFW Test Extensions U", AverageThreshold: 5, BurstThreshold: 10, ClientIdentifier: "ip", UseXForwardForHeaders: true, RequestType: "ClientRequest", SameActionOnIpv6: false, Path: struct { - PositiveMatch bool "json:\"positiveMatch\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Values: []string{"/login/", "/path/"}}, PathMatchType: "Custom", PathURIPositiveMatch: true, FileExtensions: struct { - PositiveMatch bool "json:\"positiveMatch\"" - Values []string "json:\"values\"" - }{PositiveMatch: false, Values: []string{"3g2", "3gp", "aif", "aiff", "au", "avi", "bin", "bmp", "cab"}}, Hostnames: []string{"www.ludin.org"}, AdditionalMatchOptions: []struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Type: "IpAddressCondition", Values: []string{"198.129.76.39"}}, struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Type: "RequestMethodCondition", Values: []string{"GET"}}}, QueryParameters: []struct { - Name string "json:\"name\"" - Values []string "json:\"values\"" - PositiveMatch bool "json:\"positiveMatch\"" - ValueInRange bool "json:\"valueInRange\"" - }{struct { - Name string "json:\"name\"" - Values []string "json:\"values\"" - PositiveMatch bool "json:\"positiveMatch\"" - ValueInRange bool "json:\"valueInRange\"" - }{Name: "productId", Values: []string{"BUB_12", "SUSH_11"}, PositiveMatch: true, ValueInRange: false}}, CreateDate: "", UpdateDate: "", Used: false}, + appsec.UpdateRatePolicyRequest{RatePolicyID: 134644, PolicyID: 0, ConfigID: 43253, ConfigVersion: 7, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x57, 0x41, 0x46, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x54, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x61, 0x74, 0x68, 0x73, 0x20, 0x33, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x46, 0x57, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x55, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x3a, 0x20, 0x35, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x72, 0x73, 0x74, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x73, 0x65, 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x46, 0x6f, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x6e, 0x49, 0x70, 0x76, 0x36, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2f, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x55, 0x72, 0x69, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x33, 0x67, 0x32, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x33, 0x67, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x69, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x69, 0x66, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x75, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x76, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x69, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x6d, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x62, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x49, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x32, 0x39, 0x2e, 0x37, 0x36, 0x2e, 0x33, 0x39, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x45, 0x54, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x71, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x42, 0x55, 0x42, 0x5f, 0x31, 0x32, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x55, 0x53, 0x48, 0x5f, 0x31, 0x31, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, ).Return(&cu, nil) client.On("CreateRatePolicy", mock.Anything, // ctx is irrelevant for this test - appsec.CreateRatePolicyRequest{ConfigID: 43253, ConfigVersion: 7, MatchType: "path", Type: "WAF", Name: "Test_Paths 3", Description: "AFW Test Extensions", AverageThreshold: 5, BurstThreshold: 10, ClientIdentifier: "ip", UseXForwardForHeaders: true, RequestType: "ClientRequest", SameActionOnIpv6: false, Path: struct { - PositiveMatch bool "json:\"positiveMatch\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Values: []string{"/login/", "/path/"}}, PathMatchType: "Custom", PathURIPositiveMatch: true, FileExtensions: struct { - PositiveMatch bool "json:\"positiveMatch\"" - Values []string "json:\"values\"" - }{PositiveMatch: false, Values: []string{"3g2", "3gp", "aif", "aiff", "au", "avi", "bin", "bmp", "cab"}}, Hostnames: []string{"www.ludin.org"}, AdditionalMatchOptions: []struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Type: "IpAddressCondition", Values: []string{"198.129.76.39"}}, struct { - PositiveMatch bool "json:\"positiveMatch\"" - Type string "json:\"type\"" - Values []string "json:\"values\"" - }{PositiveMatch: true, Type: "RequestMethodCondition", Values: []string{"GET"}}}, QueryParameters: []struct { - Name string "json:\"name\"" - Values []string "json:\"values\"" - PositiveMatch bool "json:\"positiveMatch\"" - ValueInRange bool "json:\"valueInRange\"" - }{struct { - Name string "json:\"name\"" - Values []string "json:\"values\"" - PositiveMatch bool "json:\"positiveMatch\"" - ValueInRange bool "json:\"valueInRange\"" - }{Name: "productId", Values: []string{"BUB_12", "SUSH_11"}, PositiveMatch: true, ValueInRange: false}}, CreateDate: "", UpdateDate: "", Used: false}, + appsec.CreateRatePolicyRequest{ID: 0, PolicyID: 0, ConfigID: 43253, ConfigVersion: 7, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x57, 0x41, 0x46, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x54, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x61, 0x74, 0x68, 0x73, 0x20, 0x33, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x46, 0x57, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x3a, 0x20, 0x35, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x72, 0x73, 0x74, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x3a, 0x20, 0x31, 0x30, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x73, 0x65, 0x58, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x46, 0x6f, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x61, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x6e, 0x49, 0x70, 0x76, 0x36, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2f, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x55, 0x72, 0x69, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x33, 0x67, 0x32, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x33, 0x67, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x69, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x69, 0x66, 0x66, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x75, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x76, 0x69, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x69, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x6d, 0x70, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x62, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x49, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x32, 0x39, 0x2e, 0x37, 0x36, 0x2e, 0x33, 0x39, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x45, 0x54, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x71, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x42, 0x55, 0x42, 0x5f, 0x31, 0x32, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x55, 0x53, 0x48, 0x5f, 0x31, 0x31, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0xa, 0x7d, 0xa}}, ).Return(&crpol, nil) client.On("RemoveRatePolicy", @@ -113,14 +57,14 @@ func TestAccAkamaiRatePolicy_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResRatePolicy/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_rate_policy.test", "id", "134644"), + resource.TestCheckResourceAttr("akamai_appsec_rate_policy.test", "id", "43253:7:134644"), ), }, { Config: loadFixtureString("testdata/TestResRatePolicy/update_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_rate_policy.test", "id", "134644"), + resource.TestCheckResourceAttr("akamai_appsec_rate_policy.test", "id", "43253:7:134644"), ), }, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_rate_protection.go b/pkg/providers/appsec/resource_akamai_appsec_rate_protection.go index 152bfd900..680dca745 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rate_protection.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rate_protection.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -57,25 +58,43 @@ func resourceRateProtectionRead(ctx context.Context, d *schema.ResourceData, m i logger := meta.Log("APPSEC", "resourceRateProtectionRead") getRateProtection := appsec.GetRateProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRateProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRateProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRateProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRateProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRateProtection.PolicyID = policyid + policyid := s[2] + getRateProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRateProtection.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRateProtection.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRateProtection.PolicyID = policyid + } rateprotection, err := client.GetRateProtection(ctx, getRateProtection) if err != nil { logger.Errorf("calling 'getRateProtection': %s", err.Error()) @@ -96,7 +115,18 @@ func resourceRateProtectionRead(ctx context.Context, d *schema.ResourceData, m i return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getRateProtection.ConfigID)) + if err := d.Set("config_id", getRateProtection.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getRateProtection.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getRateProtection.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d:%s", getRateProtection.ConfigID, getRateProtection.Version, getRateProtection.PolicyID)) return nil } @@ -108,25 +138,43 @@ func resourceRateProtectionDelete(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceRateProtectionRemove") removeRateProtection := appsec.UpdateRateProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRateProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeRateProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRateProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeRateProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRateProtection.PolicyID = policyid + policyid := s[2] + removeRateProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRateProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRateProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRateProtection.PolicyID = policyid + } removeRateProtection.ApplyRateControls = false _, errd := client.UpdateRateProtection(ctx, removeRateProtection) @@ -144,25 +192,43 @@ func resourceRateProtectionUpdate(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceRateProtectionUpdate") updateRateProtection := appsec.UpdateRateProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRateProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRateProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRateProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRateProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRateProtection.PolicyID = policyid + policyid := s[2] + updateRateProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRateProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRateProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRateProtection.PolicyID = policyid + } applyratecontrols, err := tools.GetBoolValue("enabled", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis.go new file mode 100644 index 000000000..497e99ead --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis.go @@ -0,0 +1,242 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceReputationAnalysis() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceReputationAnalysisUpdate, + ReadContext: resourceReputationAnalysisRead, + UpdateContext: resourceReputationAnalysisUpdate, + DeleteContext: resourceReputationAnalysisDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Required: true, + }, + "forward_to_http_header": { + Type: schema.TypeBool, + Required: true, + }, + "forward_shared_ip_to_http_header_siem": { + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceReputationAnalysisUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceReputationAnalysisUpdate") + + updateReputationAnalysis := appsec.UpdateReputationAnalysisRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationAnalysis.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationAnalysis.Version = version + + policyid := s[2] + updateReputationAnalysis.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationAnalysis.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationAnalysis.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationAnalysis.PolicyID = policyid + } + forwardToHttpHeader, err := tools.GetBoolValue("forward_to_http_header", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationAnalysis.ForwardToHTTPHeader = forwardToHttpHeader + + forwardSharedIpToHttpHeaderSiem, err := tools.GetBoolValue("forward_shared_ip_to_http_header_siem", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationAnalysis.ForwardSharedIPToHTTPHeaderAndSIEM = forwardSharedIpToHttpHeaderSiem + + _, erru := client.UpdateReputationAnalysis(ctx, updateReputationAnalysis) + if erru != nil { + logger.Errorf("calling 'updateReputationAnalysis': %s", erru.Error()) + return diag.FromErr(erru) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", updateReputationAnalysis.ConfigID, updateReputationAnalysis.Version, updateReputationAnalysis.PolicyID)) + + return resourceReputationAnalysisRead(ctx, d, m) +} + +func resourceReputationAnalysisDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceReputationAnalysisRemove") + + RemoveReputationAnalysis := appsec.RemoveReputationAnalysisRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + RemoveReputationAnalysis.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + RemoveReputationAnalysis.Version = version + + policyid := s[2] + RemoveReputationAnalysis.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + RemoveReputationAnalysis.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + RemoveReputationAnalysis.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + RemoveReputationAnalysis.PolicyID = policyid + } + RemoveReputationAnalysis.ForwardToHTTPHeader = false + + RemoveReputationAnalysis.ForwardSharedIPToHTTPHeaderAndSIEM = false + + _, erru := client.RemoveReputationAnalysis(ctx, RemoveReputationAnalysis) + if erru != nil { + logger.Errorf("calling 'RemoveReputationAnalysis': %s", erru.Error()) + return diag.FromErr(erru) + } + + d.SetId("") + + return nil +} + +func resourceReputationAnalysisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceReputationAnalysisRead") + + getReputationAnalysis := appsec.GetReputationAnalysisRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationAnalysis.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationAnalysis.Version = version + + policyid := s[2] + getReputationAnalysis.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationAnalysis.PolicyID = policyid + } + _, errg := client.GetReputationAnalysis(ctx, getReputationAnalysis) + if errg != nil { + logger.Errorf("calling 'getReputationAnalysis': %s", errg.Error()) + return diag.FromErr(errg) + } + + if err := d.Set("config_id", getReputationAnalysis.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getReputationAnalysis.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getReputationAnalysis.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d:%s", getReputationAnalysis.ConfigID, getReputationAnalysis.Version, getReputationAnalysis.PolicyID)) + + return nil +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis_test.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis_test.go new file mode 100644 index 000000000..b0cbc9046 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_analysis_test.go @@ -0,0 +1,67 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiReputationAnalysis_res_basic(t *testing.T) { + t.Run("match by ReputationAnalysis ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateReputationAnalysisResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResReputationAnalysis/ReputationAnalysisUpdated.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetReputationAnalysisResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResReputationAnalysis/ReputationAnalysis.json")) + json.Unmarshal([]byte(expectJS), &cr) + + cd := appsec.RemoveReputationAnalysisResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResReputationAnalysis/ReputationAnalysisDelete.json")) + json.Unmarshal([]byte(expectJSD), &cd) + + client.On("GetReputationAnalysis", + mock.Anything, // ctx is irrelevant for this test + appsec.GetReputationAnalysisRequest{ConfigID: 43253, Version: 12, PolicyID: "AAAA_81230"}, + ).Return(&cr, nil) + + client.On("UpdateReputationAnalysis", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateReputationAnalysisRequest{ConfigID: 43253, Version: 12, PolicyID: "AAAA_81230", ForwardToHTTPHeader: true, ForwardSharedIPToHTTPHeaderAndSIEM: true}, + ).Return(&cu, nil) + + client.On("RemoveReputationAnalysis", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveReputationAnalysisRequest{ConfigID: 43253, Version: 12, PolicyID: "AAAA_81230", ForwardToHTTPHeader: false, ForwardSharedIPToHTTPHeaderAndSIEM: false}, + ).Return(&cd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResReputationAnalysis/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_reputation_profile_analysis.test", "id", "43253:12:AAAA_81230"), + ), + }, + { + Config: loadFixtureString("testdata/TestResReputationAnalysis/update_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_reputation_profile_analysis.test", "id", "43253:12:AAAA_81230"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile.go index ff41227b9..a229bec61 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile.go +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -38,9 +39,10 @@ func resourceReputationProfile() *schema.Resource { Required: true, }, "reputation_profile": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsJSON, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentJsonDiffsGeneric, }, "reputation_profile_id": { Type: schema.TypeInt, @@ -63,8 +65,6 @@ func resourceReputationProfileCreate(ctx context.Context, d *schema.ResourceData createReputationProfile.JsonPayloadRaw = rawJSON - logger.Errorf("calling 'createReputationProfile JSONRAW ': %s", rawJSON) - configid, err := tools.GetIntValue("config_id", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) @@ -83,7 +83,7 @@ func resourceReputationProfileCreate(ctx context.Context, d *schema.ResourceData return diag.FromErr(errc) } - d.SetId(strconv.Itoa(postresp.ID)) + d.SetId(fmt.Sprintf("%d:%d:%d", createReputationProfile.ConfigID, createReputationProfile.ConfigVersion, postresp.ID)) return resourceReputationProfileRead(ctx, d, m) } @@ -100,25 +100,47 @@ func resourceReputationProfileUpdate(ctx context.Context, d *schema.ResourceData rawJSON := (json.RawMessage)(jsonPayloadRaw) updateReputationProfile.JsonPayloadRaw = rawJSON - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProfile.ConfigID = configid - - configversion, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProfile.ConfigVersion = configversion - - reputationProfileId, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfile.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfile.ConfigVersion = version + + reputationProfileId, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfile.ReputationProfileId = reputationProfileId + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfile.ConfigID = configid + + configversion, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfile.ConfigVersion = configversion + + reputationProfileId, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfile.ReputationProfileId = reputationProfileId } - updateReputationProfile.ReputationProfileId = reputationProfileId - _, erru := client.UpdateReputationProfile(ctx, updateReputationProfile) if erru != nil { logger.Errorf("calling 'updateReputationProfile': %s", erru.Error()) @@ -134,26 +156,47 @@ func resourceReputationProfileDelete(ctx context.Context, d *schema.ResourceData logger := meta.Log("APPSEC", "resourceReputationProfileRemove") removeReputationProfile := appsec.RemoveReputationProfileRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProfile.ConfigID = configid - - configversion, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfile.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfile.ConfigVersion = version + + reputationProfileId, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfile.ReputationProfileId = reputationProfileId + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfile.ConfigID = configid + + configversion, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfile.ConfigVersion = configversion + + reputationProfileId, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfile.ReputationProfileId = reputationProfileId } - removeReputationProfile.ConfigVersion = configversion - - reputationProfileId, errconv := strconv.Atoi(d.Id()) - - if errconv != nil { - return diag.FromErr(errconv) - } - removeReputationProfile.ReputationProfileId = reputationProfileId - _, errd := client.RemoveReputationProfile(ctx, removeReputationProfile) if errd != nil { logger.Errorf("calling 'removeReputationProfile': %s", errd.Error()) @@ -172,36 +215,75 @@ func resourceReputationProfileRead(ctx context.Context, d *schema.ResourceData, getReputationProfile := appsec.GetReputationProfileRequest{} - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfile.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfile.ConfigVersion = version + + reputationProfileId, errconv := strconv.Atoi(s[2]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfile.ReputationProfileId = reputationProfileId + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfile.ConfigID = configid + + configversion, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfile.ConfigVersion = configversion + + reputationProfileId, errconv := strconv.Atoi(d.Id()) + + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfile.ReputationProfileId = reputationProfileId + } + reputationprofile, err := client.GetReputationProfile(ctx, getReputationProfile) + if err != nil { + logger.Errorf("calling 'getReputationProfile': %s", err.Error()) return diag.FromErr(err) } - getReputationProfile.ConfigID = configid - configversion, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("reputation_profile_id", reputationprofile.ID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getReputationProfile.ConfigVersion = configversion - reputationProfileId, errconv := strconv.Atoi(d.Id()) + if err := d.Set("config_id", getReputationProfile.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - if errconv != nil { - return diag.FromErr(errconv) + if err := d.Set("version", getReputationProfile.ConfigVersion); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getReputationProfile.ReputationProfileId = reputationProfileId - reputationprofile, err := client.GetReputationProfile(ctx, getReputationProfile) + jsonBody, err := json.Marshal(reputationprofile) if err != nil { - logger.Errorf("calling 'getReputationProfile': %s", err.Error()) return diag.FromErr(err) } - if err := d.Set("reputation_profile_id", reputationprofile.ID); err != nil { + if err := d.Set("reputation_profile", string(jsonBody)); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(reputationprofile.ID)) + d.SetId(fmt.Sprintf("%d:%d:%d", getReputationProfile.ConfigID, getReputationProfile.ConfigVersion, reputationprofile.ID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action.go index ea6bd1efc..341c116ec 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -58,42 +59,78 @@ func resourceReputationProfileActionRead(ctx context.Context, d *schema.Resource logger := meta.Log("APPSEC", "resourceReputationProfileActionRead") getReputationProfileAction := appsec.GetReputationProfileActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfileAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfileAction.Version = version + + policyid := s[2] + getReputationProfileAction.PolicyID = policyid + + reputationprofileid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProfileAction.ReputationProfileID = reputationprofileid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfileAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfileAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfileAction.PolicyID = policyid + + reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProfileAction.ReputationProfileID = reputationprofileid } - getReputationProfileAction.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + resp, errr := client.GetReputationProfileAction(ctx, getReputationProfileAction) + if errr != nil { + logger.Errorf("calling 'getReputationProfileAction': %s", errr.Error()) + return diag.FromErr(errr) } - getReputationProfileAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("action", resp.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getReputationProfileAction.PolicyID = policyid - reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if err := d.Set("config_id", getReputationProfileAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - getReputationProfileAction.ReputationProfileID = reputationprofileid - resp, errr := client.GetReputationProfileAction(ctx, getReputationProfileAction) - if errr != nil { - logger.Errorf("calling 'getReputationProfileAction': %s", errr.Error()) - return diag.FromErr(errr) + if err := d.Set("version", getReputationProfileAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - if err := d.Set("action", resp.Action); err != nil { + if err := d.Set("security_policy_id", getReputationProfileAction.PolicyID); err != nil { return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getReputationProfileAction.ConfigID)) + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getReputationProfileAction.ConfigID, getReputationProfileAction.Version, getReputationProfileAction.PolicyID, getReputationProfileAction.ReputationProfileID)) return nil } @@ -104,31 +141,55 @@ func resourceReputationProfileActionDelete(ctx context.Context, d *schema.Resour logger := meta.Log("APPSEC", "resourceReputationProfileActionRemove") removeReputationProfileAction := appsec.UpdateReputationProfileActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProfileAction.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProfileAction.Version = version - - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProfileAction.PolicyID = policyid - - reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfileAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfileAction.Version = version + + policyid := s[2] + removeReputationProfileAction.PolicyID = policyid + + reputationprofileid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProfileAction.ReputationProfileID = reputationprofileid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfileAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfileAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfileAction.PolicyID = policyid + + reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProfileAction.ReputationProfileID = reputationprofileid } - removeReputationProfileAction.ReputationProfileID = reputationprofileid - removeReputationProfileAction.Action = "none" _, errd := client.UpdateReputationProfileAction(ctx, removeReputationProfileAction) @@ -148,31 +209,55 @@ func resourceReputationProfileActionUpdate(ctx context.Context, d *schema.Resour logger := meta.Log("APPSEC", "resourceReputationProfileActionUpdate") updateReputationProfileAction := appsec.UpdateReputationProfileActionRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfileAction.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfileAction.Version = version + + policyid := s[2] + updateReputationProfileAction.PolicyID = policyid + + reputationprofileid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProfileAction.ReputationProfileID = reputationprofileid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfileAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfileAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfileAction.PolicyID = policyid + + reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProfileAction.ReputationProfileID = reputationprofileid } - updateReputationProfileAction.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProfileAction.Version = version - - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProfileAction.PolicyID = policyid - - reputationprofileid, err := tools.GetIntValue("reputation_profile_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProfileAction.ReputationProfileID = reputationprofileid - action, err := tools.GetStringValue("action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) @@ -184,6 +269,7 @@ func resourceReputationProfileActionUpdate(ctx context.Context, d *schema.Resour logger.Errorf("calling 'updateReputationProfileAction': %s", erru.Error()) return diag.FromErr(erru) } - d.SetId(strconv.Itoa(reputationprofileid)) + d.SetId(fmt.Sprintf("%d:%d:%s:%d", updateReputationProfileAction.ConfigID, updateReputationProfileAction.Version, updateReputationProfileAction.PolicyID, updateReputationProfileAction.ReputationProfileID)) + return resourceReputationProfileActionRead(ctx, d, m) } diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action_test.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action_test.go index e8146a5be..f19d81ddf 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_profile_action_test.go @@ -48,7 +48,7 @@ func TestAccAkamaiReputationProfileAction_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResReputationProfileAction/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_reputation_profile_action.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_reputation_profile_action.test", "id", "43253:7:AAAA_81230:1685099"), ), ExpectNonEmptyPlan: true, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_reputation_protection.go b/pkg/providers/appsec/resource_akamai_appsec_reputation_protection.go index 6606fa67c..ccac392e5 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_reputation_protection.go +++ b/pkg/providers/appsec/resource_akamai_appsec_reputation_protection.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -57,25 +58,43 @@ func resourceReputationProtectionRead(ctx context.Context, d *schema.ResourceDat logger := meta.Log("APPSEC", "resourceReputationProtectionRead") getReputationProtection := appsec.GetReputationProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getReputationProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getReputationProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getReputationProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getReputationProtection.PolicyID = policyid + policyid := s[2] + getReputationProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProtection.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProtection.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getReputationProtection.PolicyID = policyid + } reputationprotection, err := client.GetReputationProtection(ctx, getReputationProtection) if err != nil { logger.Errorf("calling 'getReputationProtection': %s", err.Error()) @@ -96,7 +115,18 @@ func resourceReputationProtectionRead(ctx context.Context, d *schema.ResourceDat return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getReputationProtection.ConfigID)) + if err := d.Set("config_id", getReputationProtection.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getReputationProtection.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getReputationProtection.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d:%s", getReputationProtection.ConfigID, getReputationProtection.Version, getReputationProtection.PolicyID)) return nil } @@ -108,25 +138,43 @@ func resourceReputationProtectionDelete(ctx context.Context, d *schema.ResourceD logger := meta.Log("APPSEC", "resourceReputationProtectionRemove") removeReputationProtection := appsec.UpdateReputationProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeReputationProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeReputationProtection.PolicyID = policyid + policyid := s[2] + removeReputationProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeReputationProtection.PolicyID = policyid + } removeReputationProtection.ApplyReputationControls = false _, errd := client.UpdateReputationProtection(ctx, removeReputationProtection) @@ -145,25 +193,43 @@ func resourceReputationProtectionUpdate(ctx context.Context, d *schema.ResourceD logger := meta.Log("APPSEC", "resourceReputationProtectionUpdate") updateReputationProtection := appsec.UpdateReputationProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateReputationProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateReputationProtection.PolicyID = policyid + policyid := s[2] + updateReputationProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateReputationProtection.PolicyID = policyid + } applyreputationcontrols, err := tools.GetBoolValue("enabled", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_rule_action.go b/pkg/providers/appsec/resource_akamai_appsec_rule_action.go index 7add8387a..8ed8ef797 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rule_action.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rule_action.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -47,11 +48,6 @@ func resourceRuleAction() *schema.Resource { Type: schema.TypeInt, Required: true, }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -62,48 +58,80 @@ func resourceRuleActionRead(ctx context.Context, d *schema.ResourceData, m inter logger := meta.Log("APPSEC", "resourceRuleActionRead") getRuleAction := appsec.GetRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleAction.PolicyID = policyid + policyid := s[2] + getRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleAction.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleAction.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleAction.RuleID = ruleid + } ruleaction, err := client.GetRuleAction(ctx, getRuleAction) if err != nil { logger.Errorf("calling 'getRuleAction': %s", err.Error()) return diag.FromErr(err) } - ots := OutputTemplates{} - InitTemplates(ots) + if err := d.Set("config_id", getRuleAction.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } - outputtext, err := RenderTemplates(ots, "RuleAction", ruleaction) - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } + if err := d.Set("version", getRuleAction.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getRuleAction.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("rule_id", getRuleAction.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getRuleAction.ConfigID)) + if err := d.Set("rule_action", ruleaction.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getRuleAction.ConfigID, getRuleAction.Version, getRuleAction.PolicyID, getRuleAction.RuleID)) return nil } @@ -115,31 +143,54 @@ func resourceRuleActionDelete(ctx context.Context, d *schema.ResourceData, m int logger := meta.Log("APPSEC", "resourceRuleActionRemove") updateRuleAction := appsec.UpdateRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.PolicyID = policyid + policyid := s[2] + updateRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.RuleID = ruleid + } updateRuleAction.Action = "none" _, erru := client.UpdateRuleAction(ctx, updateRuleAction) @@ -158,31 +209,54 @@ func resourceRuleActionUpdate(ctx context.Context, d *schema.ResourceData, m int logger := meta.Log("APPSEC", "resourceRuleActionUpdate") updateRuleAction := appsec.UpdateRuleActionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.PolicyID = policyid + policyid := s[2] + updateRuleAction.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleAction.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleAction.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleAction.RuleID = ruleid + } ruleaction, err := tools.GetStringValue("rule_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_rule_action_test.go b/pkg/providers/appsec/resource_akamai_appsec_rule_action_test.go index 1e5b12fb5..f31dcd206 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rule_action_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rule_action_test.go @@ -39,8 +39,9 @@ func TestAccAkamaiRuleAction_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResRuleAction/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_rule_action.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_rule_action.test", "id", "43253:7:AAAA_81230:699989"), ), + ExpectNonEmptyPlan: true, }, }, }) diff --git a/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception.go b/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception.go index f101a3dba..679672347 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -50,11 +51,6 @@ func resourceRuleConditionException() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: suppressEquivalentJSONDiffsConditionException, }, - "output_text": { - Type: schema.TypeString, - Computed: true, - Description: "Text Export representation", - }, }, } } @@ -65,48 +61,60 @@ func resourceRuleConditionExceptionRead(ctx context.Context, d *schema.ResourceD logger := meta.Log("APPSEC", "resourceRuleConditionExceptionRead") getRuleConditionException := appsec.GetRuleConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleConditionException.PolicyID = policyid + policyid := s[2] + getRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getRuleConditionException.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + getRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleConditionException.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleConditionException.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getRuleConditionException.RuleID = ruleid + } ruleconditionexception, err := client.GetRuleConditionException(ctx, getRuleConditionException) if err != nil { logger.Errorf("calling 'getRuleConditionException': %s", err.Error()) return diag.FromErr(err) } - ots := OutputTemplates{} - InitTemplates(ots) - - outputtext, err := RenderTemplates(ots, "RuleConditionExceptions", ruleconditionexception) - - if err == nil { - if err := d.Set("output_text", outputtext); err != nil { - return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) - } - } - jsonBody, err := json.Marshal(ruleconditionexception) if err != nil { return diag.FromErr(err) @@ -116,7 +124,23 @@ func resourceRuleConditionExceptionRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getRuleConditionException.ConfigID)) + if err := d.Set("config_id", getRuleConditionException.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getRuleConditionException.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getRuleConditionException.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("rule_id", getRuleConditionException.RuleID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s:%d", getRuleConditionException.ConfigID, getRuleConditionException.Version, getRuleConditionException.PolicyID, getRuleConditionException.RuleID)) return nil } @@ -128,33 +152,55 @@ func resourceRuleConditionExceptionDelete(ctx context.Context, d *schema.Resourc logger := meta.Log("APPSEC", "resourceRuleConditionExceptionRemove") removeRuleConditionException := appsec.RemoveRuleConditionExceptionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRuleConditionException.PolicyID = policyid + policyid := s[2] + removeRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeRuleConditionException.RuleID = ruleid + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRuleConditionException.ConfigID = configid - logger.Errorf("calling 'RemoveRuleConditionException': %v", removeRuleConditionException) + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRuleConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRuleConditionException.PolicyID = policyid + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeRuleConditionException.RuleID = ruleid + + } _, errd := client.RemoveRuleConditionException(ctx, removeRuleConditionException) if errd != nil { logger.Errorf("calling 'RemoveRuleConditionException': %s", errd.Error()) @@ -175,34 +221,57 @@ func resourceRuleConditionExceptionUpdate(ctx context.Context, d *schema.Resourc jsonpostpayload := d.Get("condition_exception") - if err := json.Unmarshal([]byte(jsonpostpayload.(string)), &updateRuleConditionException); err != nil { - return diag.FromErr(err) - } + jsonPayloadRaw := []byte(jsonpostpayload.(string)) + rawJSON := (json.RawMessage)(jsonPayloadRaw) + updateRuleConditionException.JsonPayloadRaw = rawJSON + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleConditionException.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleConditionException.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleConditionException.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleConditionException.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateRuleConditionException.PolicyID = policyid + policyid := s[2] + updateRuleConditionException.PolicyID = policyid - ruleid, err := tools.GetIntValue("rule_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + ruleid, errconv := strconv.Atoi(s[3]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateRuleConditionException.RuleID = ruleid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleConditionException.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleConditionException.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleConditionException.PolicyID = policyid + + ruleid, err := tools.GetIntValue("rule_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateRuleConditionException.RuleID = ruleid } - updateRuleConditionException.RuleID = ruleid - logger.Errorf("calling 'updateRuleConditionException': %s", updateRuleConditionException) _, erru := client.UpdateRuleConditionException(ctx, updateRuleConditionException) if erru != nil { logger.Errorf("calling 'updateRuleConditionException': %s", erru.Error()) diff --git a/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception_test.go b/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception_test.go index e44b0346a..f9937b984 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_rule_condition_exception_test.go @@ -32,76 +32,7 @@ func TestAccAkamaiRuleConditionException_res_basic(t *testing.T) { client.On("UpdateRuleConditionException", mock.Anything, // ctx is irrelevant for this test - appsec.UpdateRuleConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", RuleID: 12345, Conditions: []struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "extensionMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "filenameMatch", Filenames: []string{"test2"}, PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "hostMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "ipMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "uriQueryMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "requestHeaderMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "requestMethodMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string{"GET"}}, struct { - Type string "json:\"type\"" - Filenames []string "json:\"filenames,omitempty\"" - PositiveMatch bool "json:\"positiveMatch\"" - Methods []string "json:\"methods,omitempty\"" - }{Type: "pathMatch", Filenames: []string(nil), PositiveMatch: true, Methods: []string(nil)}}, Exception: struct { - HeaderCookieOrParamValues []string "json:\"headerCookieOrParamValues\"" - SpecificHeaderCookieOrParamNames []struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - } "json:\"specificHeaderCookieOrParamNames\"" - }{HeaderCookieOrParamValues: []string{"test"}, SpecificHeaderCookieOrParamNames: []struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{Names: []string{"test"}, Selector: "REQUEST_HEADERS"}, struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{Names: []string{"test"}, Selector: "REQUEST_COOKIES"}, struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{Names: []string{"test"}, Selector: "ARGS"}, struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{Names: []string{"test"}, Selector: "JSON_PAIRS"}, struct { - Names []string "json:\"names\"" - Selector string "json:\"selector\"" - }{Names: []string{"test"}, Selector: "XML_PAIRS"}}}}, + appsec.UpdateRuleConditionExceptionRequest{ConfigID: 43253, Version: 7, PolicyID: "AAAA_81230", RuleID: 12345, JsonPayloadRaw: json.RawMessage{0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x32, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x69, 0x70, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x70, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x31, 0x32, 0x33, 0x2e, 0x31, 0x32, 0x33, 0x2e, 0x31, 0x32, 0x33, 0x2e, 0x31, 0x32, 0x33, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x75, 0x72, 0x69, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x73, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x33, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x34, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x35, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x22, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x45, 0x54, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x36, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x3a, 0x20, 0x74, 0x72, 0x75, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x53, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x43, 0x4f, 0x4f, 0x4b, 0x49, 0x45, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x52, 0x47, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x4a, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x49, 0x52, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x58, 0x4d, 0x4c, 0x5f, 0x50, 0x41, 0x49, 0x52, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x4f, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x7b, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3a, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x2c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x53, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x20, 0x20, 0x20, 0x20, 0x7d, 0xa, 0x7d, 0xa}}, ).Return(&cu, nil) client.On("RemoveRuleConditionException", @@ -117,7 +48,7 @@ func TestAccAkamaiRuleConditionException_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResRuleConditionException/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_rule_condition_exception.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_rule_condition_exception.test", "id", "43253:7:AAAA_81230:12345"), ), }, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_security_policy.go b/pkg/providers/appsec/resource_akamai_appsec_security_policy.go index 0715092c5..9a3de919e 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_security_policy.go +++ b/pkg/providers/appsec/resource_akamai_appsec_security_policy.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -21,6 +23,9 @@ func resourceSecurityPolicy() *schema.Resource { ReadContext: resourceSecurityPolicyRead, UpdateContext: resourceSecurityPolicyUpdate, DeleteContext: resourceSecurityPolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "config_id": { Type: schema.TypeInt, @@ -32,11 +37,16 @@ func resourceSecurityPolicy() *schema.Resource { }, "security_policy_name": { Type: schema.TypeString, - Optional: true, + Required: true, }, "security_policy_prefix": { Type: schema.TypeString, + Required: true, + }, + "default_settings": { + Type: schema.TypeBool, Optional: true, + Default: true, }, "security_policy_id": &schema.Schema{ Type: schema.TypeString, @@ -72,6 +82,12 @@ func resourceSecurityPolicyCreate(ctx context.Context, d *schema.ResourceData, m } createSecurityPolicy.PolicyName = policyname + defaultSettings, err := tools.GetBoolValue("default_settings", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + createSecurityPolicy.DefaultSettings = defaultSettings + policyprefix, err := tools.GetStringValue("security_policy_prefix", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) @@ -92,49 +108,12 @@ func resourceSecurityPolicyCreate(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(spcr.PolicyID) + d.SetId(fmt.Sprintf("%d:%d:%s", createSecurityPolicy.ConfigID, createSecurityPolicy.Version, spcr.PolicyID)) return resourceSecurityPolicyRead(ctx, d, m) } func resourceSecurityPolicyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - meta := akamai.Meta(m) - client := inst.Client(meta) - logger := meta.Log("APPSEC", "resourceSecurityPolicyUpdate") - - updateSecurityPolicy := appsec.UpdateSecurityPolicyRequest{} - - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSecurityPolicy.ConfigID = configid - - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSecurityPolicy.Version = version - - policyname, err := tools.GetStringValue("security_policy_name", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSecurityPolicy.PolicyName = policyname - - policyprefix, err := tools.GetStringValue("security_policy_prefix", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSecurityPolicy.PolicyPrefix = policyprefix - - updateSecurityPolicy.PolicyID = d.Id() - - _, erru := client.UpdateSecurityPolicy(ctx, updateSecurityPolicy) - if erru != nil { - logger.Errorf("calling 'updateSecurityPolicy': %s", erru.Error()) - return diag.FromErr(erru) - } return resourceSecurityPolicyRead(ctx, d, m) } @@ -145,21 +124,40 @@ func resourceSecurityPolicyDelete(ctx context.Context, d *schema.ResourceData, m logger := meta.Log("APPSEC", "resourceSecurityPolicyRemove") removeSecurityPolicy := appsec.RemoveSecurityPolicyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeSecurityPolicy.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSecurityPolicy.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeSecurityPolicy.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSecurityPolicy.Version = version + + policyid := s[2] + + removeSecurityPolicy.PolicyID = policyid - removeSecurityPolicy.PolicyID = d.Id() + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSecurityPolicy.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSecurityPolicy.Version = version + + removeSecurityPolicy.PolicyID = d.Id() + } _, errd := client.RemoveSecurityPolicy(ctx, removeSecurityPolicy) if errd != nil { logger.Errorf("calling 'removeSecurityPolicy': %s", errd.Error()) @@ -177,21 +175,40 @@ func resourceSecurityPolicyRead(ctx context.Context, d *schema.ResourceData, m i logger := meta.Log("APPSEC", "resourceSecurityPolicyRead") getSecurityPolicy := appsec.GetSecurityPolicyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSecurityPolicy.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSecurityPolicy.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSecurityPolicy.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSecurityPolicy.Version = version + + policyid := s[2] + + getSecurityPolicy.PolicyID = policyid - getSecurityPolicy.PolicyID = d.Id() + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSecurityPolicy.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSecurityPolicy.Version = version + + getSecurityPolicy.PolicyID = d.Id() + } securitypolicy, err := client.GetSecurityPolicy(ctx, getSecurityPolicy) if err != nil { logger.Errorf("calling 'getSecurityPolicy': %s", err.Error()) @@ -206,7 +223,24 @@ func resourceSecurityPolicyRead(ctx context.Context, d *schema.ResourceData, m i return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(securitypolicy.PolicyID) + if err := d.Set("config_id", getSecurityPolicy.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getSecurityPolicy.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("default_settings", securitypolicy.DefaultSettings); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + pp := strings.Split(securitypolicy.PolicyID, "_") + if err := d.Set("security_policy_prefix", pp[0]); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getSecurityPolicy.ConfigID, getSecurityPolicy.Version, securitypolicy.PolicyID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_security_policy_protections.go b/pkg/providers/appsec/resource_akamai_appsec_security_policy_protections.go index ad5a148d0..692c62b02 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_security_policy_protections.go +++ b/pkg/providers/appsec/resource_akamai_appsec_security_policy_protections.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -81,25 +82,43 @@ func resourcePolicyProtectionsRead(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourcePolicyProtectionsRead") getPolicyProtections := appsec.GetPolicyProtectionsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPolicyProtections.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPolicyProtections.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPolicyProtections.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getPolicyProtections.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getPolicyProtections.PolicyID = policyid + policyid := s[2] + getPolicyProtections.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPolicyProtections.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPolicyProtections.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getPolicyProtections.PolicyID = policyid + } policyprotections, err := client.GetPolicyProtections(ctx, getPolicyProtections) if err != nil { logger.Errorf("calling 'getPolicyProtections': %s", err.Error()) @@ -116,7 +135,19 @@ func resourcePolicyProtectionsRead(ctx context.Context, d *schema.ResourceData, } } - d.SetId(strconv.Itoa(getPolicyProtections.ConfigID)) + if err := d.Set("config_id", getPolicyProtections.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getPolicyProtections.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getPolicyProtections.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getPolicyProtections.ConfigID, getPolicyProtections.Version, getPolicyProtections.PolicyID)) return nil } @@ -129,27 +160,49 @@ func resourcePolicyProtectionsDelete(ctx context.Context, d *schema.ResourceData updatePolicyProtections := appsec.UpdatePolicyProtectionsRequest{} removePolicyProtections := appsec.RemovePolicyProtectionsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.ConfigID = configid - removePolicyProtections.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.ConfigID = configid + removePolicyProtections.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.Version = version - removePolicyProtections.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.Version = version + removePolicyProtections.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) + policyid := s[2] + updatePolicyProtections.PolicyID = policyid + removePolicyProtections.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.ConfigID = configid + removePolicyProtections.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.Version = version + removePolicyProtections.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.PolicyID = policyid + removePolicyProtections.PolicyID = policyid } - updatePolicyProtections.PolicyID = policyid - removePolicyProtections.PolicyID = policyid //TODO remove once API fixed in Jan updatePolicyProtections.ApplyApplicationLayerControls = true @@ -201,25 +254,43 @@ func resourcePolicyProtectionsUpdate(ctx context.Context, d *schema.ResourceData logger := meta.Log("APPSEC", "resourcePolicyProtectionsUpdate") updatePolicyProtections := appsec.UpdatePolicyProtectionsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updatePolicyProtections.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updatePolicyProtections.PolicyID = policyid + policyid := s[2] + updatePolicyProtections.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updatePolicyProtections.PolicyID = policyid + } applyapplicationlayercontrols, err := tools.GetBoolValue("apply_application_layer_controls", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename.go b/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename.go new file mode 100644 index 000000000..ef2a70ef0 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename.go @@ -0,0 +1,178 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceSecurityPolicyRename() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceSecurityPolicyRenameUpdate, + ReadContext: resourceSecurityPolicyRenameRead, + UpdateContext: resourceSecurityPolicyRenameUpdate, + DeleteContext: resourceSecurityPolicyRenameDelete, + + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_name": { + Type: schema.TypeString, + Required: true, + }, + "security_policy_id": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceSecurityPolicyRenameUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceSecurityPolicyUpdate") + + updateSecurityPolicy := appsec.UpdateSecurityPolicyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSecurityPolicy.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSecurityPolicy.Version = version + + policyid := s[2] + + updateSecurityPolicy.PolicyID = policyid + + policyname, err := tools.GetStringValue("security_policy_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSecurityPolicy.PolicyName = policyname + + } else { + + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSecurityPolicy.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSecurityPolicy.Version = version + + securitypolicyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + + updateSecurityPolicy.PolicyID = securitypolicyid + + policyname, err := tools.GetStringValue("security_policy_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSecurityPolicy.PolicyName = policyname + } + _, erru := client.UpdateSecurityPolicy(ctx, updateSecurityPolicy) + if erru != nil { + logger.Errorf("calling 'updateSecurityPolicy': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceSecurityPolicyRenameRead(ctx, d, m) +} + +func resourceSecurityPolicyRenameDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + return schema.NoopContext(nil, d, m) +} + +func resourceSecurityPolicyRenameRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceSecurityPolicyRead") + + getSecurityPolicy := appsec.GetSecurityPolicyRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSecurityPolicy.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSecurityPolicy.Version = version + + policyid := s[2] + + getSecurityPolicy.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSecurityPolicy.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSecurityPolicy.Version = version + + securitypolicyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + + getSecurityPolicy.PolicyID = securitypolicyid + + } + securitypolicy, err := client.GetSecurityPolicy(ctx, getSecurityPolicy) + if err != nil { + logger.Errorf("calling 'getSecurityPolicy': %s", err.Error()) + return diag.FromErr(err) + } + + /*if err := d.Set("security_policy_name", securitypolicy.PolicyName); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + }*/ + + d.SetId(fmt.Sprintf("%d:%d:%s", getSecurityPolicy.ConfigID, getSecurityPolicy.Version, securitypolicy.PolicyID)) + + return nil +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename_test.go b/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename_test.go new file mode 100644 index 000000000..15bb5c90e --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_security_policy_rename_test.go @@ -0,0 +1,60 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiSecurityPolicyRename_res_basic(t *testing.T) { + t.Run("match by SecurityPolicy ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateSecurityPolicyResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResSecurityPolicyRename/SecurityPolicyUpdate.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetSecurityPolicyResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResSecurityPolicyRename/SecurityPolicy.json")) + json.Unmarshal([]byte(expectJS), &cr) + + client.On("GetSecurityPolicy", + mock.Anything, // ctx is irrelevant for this test + appsec.GetSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyID: "PLE_114049"}, + ).Return(&cr, nil) + + client.On("UpdateSecurityPolicy", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyID: "PLE_114049", PolicyName: "Cloned Test for Launchpad 15", DefaultSettings: false, PolicyPrefix: ""}, + ).Return(&cu, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResSecurityPolicyRename/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_security_policy_rename.test", "id", "43253:7:PLE_114049"), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: loadFixtureString("testdata/TestResSecurityPolicyRename/update_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_security_policy_rename.test", "id", "43253:7:PLE_114049"), + ), + //ExpectNonEmptyPlan: true, + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_security_policy_test.go b/pkg/providers/appsec/resource_akamai_appsec_security_policy_test.go index 049c8a80f..56151bca3 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_security_policy_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_security_policy_test.go @@ -13,10 +13,6 @@ func TestAccAkamaiSecurityPolicy_res_basic(t *testing.T) { t.Run("match by SecurityPolicy ID", func(t *testing.T) { client := &mockappsec{} - cu := appsec.UpdateSecurityPolicyResponse{} - expectJSU := compactJSON(loadFixtureBytes("testdata/TestResSecurityPolicy/SecurityPolicyUpdate.json")) - json.Unmarshal([]byte(expectJSU), &cu) - cr := appsec.GetSecurityPolicyResponse{} expectJS := compactJSON(loadFixtureBytes("testdata/TestResSecurityPolicy/SecurityPolicy.json")) json.Unmarshal([]byte(expectJS), &cr) @@ -36,14 +32,9 @@ func TestAccAkamaiSecurityPolicy_res_basic(t *testing.T) { client.On("CreateSecurityPolicy", mock.Anything, // ctx is irrelevant for this test - appsec.CreateSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyName: "Cloned Test for Launchpad 15", PolicyPrefix: "LN"}, + appsec.CreateSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyName: "Cloned Test for Launchpad 15", PolicyPrefix: "LN", DefaultSettings: true}, ).Return(&crp, nil) - client.On("UpdateSecurityPolicy", - mock.Anything, // ctx is irrelevant for this test - appsec.UpdateSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyID: "PLE_114049", PolicyName: "Cloned Test for Launchpad 21", PolicyPrefix: "LN"}, - ).Return(&cu, nil) - client.On("RemoveSecurityPolicy", mock.Anything, // ctx is irrelevant for this test appsec.RemoveSecurityPolicyRequest{ConfigID: 43253, Version: 7, PolicyID: "PLE_114049"}, @@ -57,14 +48,7 @@ func TestAccAkamaiSecurityPolicy_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResSecurityPolicy/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_security_policy.test", "id", "PLE_114049"), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: loadFixtureString("testdata/TestResSecurityPolicy/update_by_id.tf"), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_security_policy.test", "id", "PLE_114049"), + resource.TestCheckResourceAttr("akamai_appsec_security_policy.test", "id", "43253:7:PLE_114049"), ), ExpectNonEmptyPlan: true, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_selected_hostname.go b/pkg/providers/appsec/resource_akamai_appsec_selected_hostname.go index 3c5e7ac56..f1d414ba9 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_selected_hostname.go +++ b/pkg/providers/appsec/resource_akamai_appsec_selected_hostname.go @@ -113,6 +113,10 @@ func resourceSelectedHostnameRead(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } + if err := d.Set("mode", "REPLACE"); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + d.SetId(fmt.Sprintf("%d:%d", getSelectedHostname.ConfigID, getSelectedHostname.Version)) return nil @@ -129,19 +133,33 @@ func resourceSelectedHostnameUpdate(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceSelectedHostnameUpdate") updateSelectedHostname := appsec.UpdateSelectedHostnameRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSelectedHostname.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSelectedHostname.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSelectedHostname.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSelectedHostname.Version = version + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSelectedHostname.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSelectedHostname.Version = version + } mode := d.Get("mode").(string) hn := appsec.GetSelectedHostnamesRequest{} @@ -155,8 +173,8 @@ func resourceSelectedHostnameUpdate(ctx context.Context, d *schema.ResourceData, } getSelectedHostnames := appsec.GetSelectedHostnamesRequest{} - getSelectedHostnames.ConfigID = configid - getSelectedHostnames.Version = version + getSelectedHostnames.ConfigID = updateSelectedHostname.ConfigID + getSelectedHostnames.Version = updateSelectedHostname.Version selectedhostnames, err := client.GetSelectedHostnames(ctx, getSelectedHostnames) if err != nil { diff --git a/pkg/providers/appsec/resource_akamai_appsec_siem_settings.go b/pkg/providers/appsec/resource_akamai_appsec_siem_settings.go new file mode 100644 index 000000000..51411bdf1 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_siem_settings.go @@ -0,0 +1,274 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + v2 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceSiemSettings() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceSiemSettingsUpdate, + ReadContext: resourceSiemSettingsRead, + UpdateContext: resourceSiemSettingsUpdate, + DeleteContext: resourceSiemSettingsDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "enable_siem": { + Type: schema.TypeBool, + Required: true, + }, + "enable_for_all_policies": { + Type: schema.TypeBool, + Required: true, + }, + "enable_botman_siem": { + Type: schema.TypeBool, + Optional: true, + }, + "siem_id": { + Type: schema.TypeInt, + Required: true, + }, + "security_policy_ids": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func resourceSiemSettingsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceSiemSettingsRead") + + getSiemSettings := v2.GetSiemSettingsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSiemSettings.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSiemSettings.Version = version + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSiemSettings.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSiemSettings.Version = version + } + siemsettings, err := client.GetSiemSettings(ctx, getSiemSettings) + if err != nil { + logger.Errorf("calling 'getSiemSettings': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "siemsettingsDS", siemsettings) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getSiemSettings.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getSiemSettings.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("enable_siem", siemsettings.EnableSiem); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("enable_for_all_policies", siemsettings.EnableForAllPolicies); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("enable_botman_siem", siemsettings.EnabledBotmanSiemEvents); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("siem_id", siemsettings.SiemDefinitionID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_ids", siemsettings.FirewallPolicyIds); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getSiemSettings.ConfigID, getSiemSettings.Version)) + + return nil +} + +func resourceSiemSettingsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceSiemSettingsUpdate") + + removeSiemSettings := v2.RemoveSiemSettingsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSiemSettings.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSiemSettings.Version = version + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSiemSettings.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSiemSettings.Version = version + } + removeSiemSettings.EnableSiem = false + + siemID, err := tools.GetIntValue("siem_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSiemSettings.SiemDefinitionID = siemID + + _, erru := client.RemoveSiemSettings(ctx, removeSiemSettings) + if erru != nil { + logger.Errorf("calling 'removeSiemSettings': %s", erru.Error()) + return diag.FromErr(erru) + } + + d.SetId("") + return nil +} + +func resourceSiemSettingsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceSiemSettingsUpdate") + + updateSiemSettings := v2.UpdateSiemSettingsRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSiemSettings.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSiemSettings.Version = version + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.Version = version + } + enableSiem, err := tools.GetBoolValue("enable_siem", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.EnableSiem = enableSiem + + enableForAllPolicies, err := tools.GetBoolValue("enable_for_all_policies", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.EnableForAllPolicies = enableForAllPolicies + + enableBotmanSiem, err := tools.GetBoolValue("enable_botman_siem", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.EnabledBotmanSiemEvents = enableBotmanSiem + + siemID, err := tools.GetIntValue("siem_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSiemSettings.SiemDefinitionID = siemID + + security_policy_ids := d.Get("security_policy_ids").([]interface{}) + spids := make([]string, 0, len(security_policy_ids)) + + for _, h := range security_policy_ids { + spids = append(spids, h.(string)) + + } + + updateSiemSettings.FirewallPolicyIds = spids + + _, erru := client.UpdateSiemSettings(ctx, updateSiemSettings) + if erru != nil { + logger.Errorf("calling 'updateSiemSettings': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceSiemSettingsRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_siem_settings_test.go b/pkg/providers/appsec/resource_akamai_appsec_siem_settings_test.go new file mode 100644 index 000000000..5d46b1901 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_siem_settings_test.go @@ -0,0 +1,62 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiSiemSettings_res_basic(t *testing.T) { + t.Run("match by SiemSettings ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateSiemSettingsResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResSiemSettings/SiemSettings.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetSiemSettingsResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResSiemSettings/SiemSettings.json")) + json.Unmarshal([]byte(expectJS), &cr) + + crd := appsec.RemoveSiemSettingsResponse{} + expectJSD := compactJSON(loadFixtureBytes("testdata/TestResSiemSettings/SiemSettings.json")) + json.Unmarshal([]byte(expectJSD), &crd) + + client.On("GetSiemSettings", + mock.Anything, // ctx is irrelevant for this test + appsec.GetSiemSettingsRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateSiemSettings", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateSiemSettingsRequest{ConfigID: 43253, Version: 7, EnableForAllPolicies: false, EnableSiem: true, EnabledBotmanSiemEvents: true, SiemDefinitionID: 1, FirewallPolicyIds: []string{"12345"}}, + ).Return(&cu, nil) + + client.On("RemoveSiemSettings", + mock.Anything, // ctx is irrelevant for this test + appsec.RemoveSiemSettingsRequest{ConfigID: 43253, Version: 7, EnableForAllPolicies: false, EnableSiem: false, EnabledBotmanSiemEvents: false, SiemDefinitionID: 1, FirewallPolicyIds: []string(nil)}, + ).Return(&crd, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResSiemSettings/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_siem_settings.test", "id", "43253:7"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_slow_post_protection_setting.go b/pkg/providers/appsec/resource_akamai_appsec_slow_post_protection_setting.go index 4abec0104..fc29b9b8d 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_slow_post_protection_setting.go +++ b/pkg/providers/appsec/resource_akamai_appsec_slow_post_protection_setting.go @@ -3,7 +3,9 @@ package appsec import ( "context" "errors" + "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -56,7 +58,8 @@ func resourceSlowPostProtectionSetting() *schema.Resource { }, "duration_threshold_timeout": { Type: schema.TypeInt, - Required: true, + Optional: true, + Default: 0, }, }, } @@ -68,32 +71,78 @@ func resourceSlowPostProtectionSettingRead(ctx context.Context, d *schema.Resour logger := meta.Log("APPSEC", "resourceSlowPostProtectionSettingRead") getSlowPostProtectionSetting := appsec.GetSlowPostProtectionSettingRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtectionSetting.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSlowPostProtectionSetting.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtectionSetting.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSlowPostProtectionSetting.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtectionSetting.PolicyID = policyid + policyid := s[2] + getSlowPostProtectionSetting.PolicyID = policyid - _, errg := client.GetSlowPostProtectionSetting(ctx, getSlowPostProtectionSetting) + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtectionSetting.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtectionSetting.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtectionSetting.PolicyID = policyid + } + getslowpost, errg := client.GetSlowPostProtectionSetting(ctx, getSlowPostProtectionSetting) if errg != nil { logger.Errorf("calling 'getSlowPostProtectionSetting': %s", errg.Error()) return diag.FromErr(errg) } - d.SetId(strconv.Itoa(getSlowPostProtectionSetting.ConfigID)) + if err := d.Set("config_id", getSlowPostProtectionSetting.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getSlowPostProtectionSetting.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getSlowPostProtectionSetting.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("slow_rate_action", getslowpost.Action); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("slow_rate_threshold_rate", getslowpost.SlowRateThreshold.Rate); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("slow_rate_threshold_period", getslowpost.SlowRateThreshold.Period); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("duration_threshold_timeout", getslowpost.DurationThreshold.Timeout); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getSlowPostProtectionSetting.ConfigID, getSlowPostProtectionSetting.Version, getSlowPostProtectionSetting.PolicyID)) return nil } @@ -105,28 +154,45 @@ func resourceSlowPostProtectionSettingDelete(ctx context.Context, d *schema.Reso logger := meta.Log("APPSEC", "resourceSlowPostProtectionSettingDelete") updateSlowPostProtection := appsec.UpdateSlowPostProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.PolicyID = policyid + policyid := s[2] + updateSlowPostProtection.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.PolicyID = policyid + } updateSlowPostProtection.ApplySlowPostControls = false - logger.Errorf("calling 'updateSlowPostProtection': %v", updateSlowPostProtection) _, erru := client.UpdateSlowPostProtection(ctx, updateSlowPostProtection) if erru != nil { logger.Errorf("calling 'updateSlowPostProtection': %s", erru.Error()) @@ -142,25 +208,43 @@ func resourceSlowPostProtectionSettingUpdate(ctx context.Context, d *schema.Reso logger := meta.Log("APPSEC", "resourceSlowPostProtectionSettingUpdate") updateSlowPostProtectionSetting := appsec.UpdateSlowPostProtectionSettingRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtectionSetting.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtectionSetting.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtectionSetting.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtectionSetting.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtectionSetting.PolicyID = policyid + policyid := s[2] + updateSlowPostProtectionSetting.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtectionSetting.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtectionSetting.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtectionSetting.PolicyID = policyid + } slowrateaction, err := tools.GetStringValue("slow_rate_action", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection.go b/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection.go index 58d1ddf6c..1962306d8 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection.go +++ b/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -57,25 +58,43 @@ func resourceSlowPostProtectionRead(ctx context.Context, d *schema.ResourceData, logger := meta.Log("APPSEC", "resourceSlowPostProtectionRead") getSlowPostProtection := appsec.GetSlowPostProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSlowPostProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getSlowPostProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getSlowPostProtection.PolicyID = policyid + policyid := s[2] + getSlowPostProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtection.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtection.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getSlowPostProtection.PolicyID = policyid + } slowpostprotection, err := client.GetSlowPostProtection(ctx, getSlowPostProtection) if err != nil { logger.Errorf("calling 'getSlowPostProtection': %s", err.Error()) @@ -96,7 +115,19 @@ func resourceSlowPostProtectionRead(ctx context.Context, d *schema.ResourceData, return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getSlowPostProtection.ConfigID)) + if err := d.Set("config_id", getSlowPostProtection.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getSlowPostProtection.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getSlowPostProtection.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getSlowPostProtection.ConfigID, getSlowPostProtection.Version, getSlowPostProtection.PolicyID)) return nil } @@ -108,25 +139,43 @@ func resourceSlowPostProtectionDelete(ctx context.Context, d *schema.ResourceDat logger := meta.Log("APPSEC", "resourceSlowPostProtectionRemove") removeSlowPostProtection := appsec.UpdateSlowPostProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeSlowPostProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSlowPostProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeSlowPostProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + removeSlowPostProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - removeSlowPostProtection.PolicyID = policyid + policyid := s[2] + removeSlowPostProtection.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSlowPostProtection.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSlowPostProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + removeSlowPostProtection.PolicyID = policyid + } removeSlowPostProtection.ApplySlowPostControls = false _, errd := client.UpdateSlowPostProtection(ctx, removeSlowPostProtection) @@ -144,25 +193,43 @@ func resourceSlowPostProtectionUpdate(ctx context.Context, d *schema.ResourceDat logger := meta.Log("APPSEC", "resourceSlowPostProtectionUpdate") updateSlowPostProtection := appsec.UpdateSlowPostProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateSlowPostProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateSlowPostProtection.PolicyID = policyid + policyid := s[2] + updateSlowPostProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateSlowPostProtection.PolicyID = policyid + } applyslowpostcontrols, err := tools.GetBoolValue("enabled", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) diff --git a/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection_test.go b/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection_test.go index 7c0b59248..f108fd55a 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_slowpost_protection_test.go @@ -39,7 +39,7 @@ func TestAccAkamaiSlowPostProtection_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResSlowPostProtection/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_slowpost_protection.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_slowpost_protection.test", "id", "43253:7:AAAA_81230"), ), }, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_version_notes.go b/pkg/providers/appsec/resource_akamai_appsec_version_notes.go new file mode 100644 index 000000000..1761d1094 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_version_notes.go @@ -0,0 +1,164 @@ +package appsec + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" + "github.com/akamai/terraform-provider-akamai/v2/pkg/tools" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// appsec v1 +// +// https://developer.akamai.com/api/cloud_security/application_security/v1.html +func resourceVersionNotes() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceVersionNotesUpdate, + ReadContext: resourceVersionNotesRead, + UpdateContext: resourceVersionNotesUpdate, + DeleteContext: resourceVersionNotesDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "config_id": { + Type: schema.TypeInt, + Required: true, + }, + "version": { + Type: schema.TypeInt, + Required: true, + }, + "version_notes": { + Type: schema.TypeString, + Required: true, + }, + "output_text": { + Type: schema.TypeString, + Computed: true, + Description: "Text Export representation", + }, + }, + } +} + +func resourceVersionNotesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceVersionNotesRead") + + getVersionNotes := appsec.GetVersionNotesRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getVersionNotes.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getVersionNotes.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getVersionNotes.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getVersionNotes.Version = version + } + versionnotes, err := client.GetVersionNotes(ctx, getVersionNotes) + if err != nil { + logger.Errorf("calling 'getVersionNotes': %s", err.Error()) + return diag.FromErr(err) + } + + ots := OutputTemplates{} + InitTemplates(ots) + + outputtext, err := RenderTemplates(ots, "versionNotesDS", versionnotes) + if err == nil { + d.Set("output_text", outputtext) + } + + if err := d.Set("config_id", getVersionNotes.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getVersionNotes.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d", getVersionNotes.ConfigID, getVersionNotes.Version)) + + return nil +} + +func resourceVersionNotesDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + + return schema.NoopContext(nil, d, m) +} + +func resourceVersionNotesUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + meta := akamai.Meta(m) + client := inst.Client(meta) + logger := meta.Log("APPSEC", "resourceVersionNotesUpdate") + + updateVersionNotes := appsec.UpdateVersionNotesRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") + + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateVersionNotes.ConfigID = configid + + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateVersionNotes.Version = version + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateVersionNotes.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateVersionNotes.Version = version + } + notes, err := tools.GetStringValue("version_notes", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateVersionNotes.Notes = notes + + _, erru := client.UpdateVersionNotes(ctx, updateVersionNotes) + if erru != nil { + logger.Errorf("calling 'updateVersionNotes': %s", erru.Error()) + return diag.FromErr(erru) + } + + return resourceVersionNotesRead(ctx, d, m) +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_version_notes_test.go b/pkg/providers/appsec/resource_akamai_appsec_version_notes_test.go new file mode 100644 index 000000000..5f17cb325 --- /dev/null +++ b/pkg/providers/appsec/resource_akamai_appsec_version_notes_test.go @@ -0,0 +1,52 @@ +package appsec + +import ( + "encoding/json" + "testing" + + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/mock" +) + +func TestAccAkamaiVersionNotes_res_basic(t *testing.T) { + t.Run("match by VersionNotes ID", func(t *testing.T) { + client := &mockappsec{} + + cu := appsec.UpdateVersionNotesResponse{} + expectJSU := compactJSON(loadFixtureBytes("testdata/TestResVersionNotes/VersionNotes.json")) + json.Unmarshal([]byte(expectJSU), &cu) + + cr := appsec.GetVersionNotesResponse{} + expectJS := compactJSON(loadFixtureBytes("testdata/TestResVersionNotes/VersionNotes.json")) + json.Unmarshal([]byte(expectJS), &cr) + + client.On("GetVersionNotes", + mock.Anything, // ctx is irrelevant for this test + appsec.GetVersionNotesRequest{ConfigID: 43253, Version: 7}, + ).Return(&cr, nil) + + client.On("UpdateVersionNotes", + mock.Anything, // ctx is irrelevant for this test + appsec.UpdateVersionNotesRequest{ConfigID: 43253, Version: 7, Notes: "Test Notes"}, + ).Return(&cu, nil) + + useClient(client, func() { + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestResVersionNotes/match_by_id.tf"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("akamai_appsec_version_notes.test", "id", "43253:7"), + ), + }, + }, + }) + }) + + client.AssertExpectations(t) + }) + +} diff --git a/pkg/providers/appsec/resource_akamai_appsec_waf_mode.go b/pkg/providers/appsec/resource_akamai_appsec_waf_mode.go index 74c6ec4fe..6880e1bdc 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_waf_mode.go +++ b/pkg/providers/appsec/resource_akamai_appsec_waf_mode.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -78,25 +79,43 @@ func resourceWAFModeRead(ctx context.Context, d *schema.ResourceData, m interfac logger := meta.Log("APPSEC", "resourceWAFModeRead") getWAFMode := appsec.GetWAFModeRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFMode.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getWAFMode.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFMode.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getWAFMode.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFMode.PolicyID = policyid + policyid := s[2] + getWAFMode.PolicyID = policyid + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFMode.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFMode.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFMode.PolicyID = policyid + } wafmode, err := client.GetWAFMode(ctx, getWAFMode) if err != nil { logger.Errorf("calling 'getWAFMode': %s", err.Error()) @@ -130,7 +149,19 @@ func resourceWAFModeRead(ctx context.Context, d *schema.ResourceData, m interfac return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) } - d.SetId(strconv.Itoa(getWAFMode.ConfigID)) + if err := d.Set("config_id", getWAFMode.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getWAFMode.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getWAFMode.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getWAFMode.ConfigID, getWAFMode.Version, getWAFMode.PolicyID)) return nil } @@ -146,25 +177,43 @@ func resourceWAFModeUpdate(ctx context.Context, d *schema.ResourceData, m interf logger := meta.Log("APPSEC", "resourceWAFModeUpdate") updateWAFMode := appsec.UpdateWAFModeRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateWAFMode.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateWAFMode.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateWAFMode.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + updateWAFMode.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - updateWAFMode.PolicyID = policyid + policyid := s[2] + updateWAFMode.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateWAFMode.ConfigID = configid + + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateWAFMode.Version = version + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + updateWAFMode.PolicyID = policyid + } mode, err := tools.GetStringValue("mode", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { return diag.FromErr(err) @@ -173,9 +222,9 @@ func resourceWAFModeUpdate(ctx context.Context, d *schema.ResourceData, m interf //if current mode = one to updare skip this call getWAFMode := appsec.GetWAFModeRequest{} - getWAFMode.ConfigID = configid - getWAFMode.Version = version - getWAFMode.PolicyID = policyid + getWAFMode.ConfigID = updateWAFMode.ConfigID + getWAFMode.Version = updateWAFMode.Version + getWAFMode.PolicyID = updateWAFMode.PolicyID wafmode, err := client.GetWAFMode(ctx, getWAFMode) if err != nil { diff --git a/pkg/providers/appsec/resource_akamai_appsec_waf_mode_test.go b/pkg/providers/appsec/resource_akamai_appsec_waf_mode_test.go index 4a718abfd..993da78f5 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_waf_mode_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_waf_mode_test.go @@ -39,7 +39,7 @@ func TestAccAkamaiWAFMode_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResWAFMode/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_waf_mode.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_waf_mode.test", "id", "43253:7:AAAA_81230"), ), }, }, diff --git a/pkg/providers/appsec/resource_akamai_appsec_waf_protection.go b/pkg/providers/appsec/resource_akamai_appsec_waf_protection.go index 83e225cb0..f254d0112 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_waf_protection.go +++ b/pkg/providers/appsec/resource_akamai_appsec_waf_protection.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/appsec" "github.com/akamai/terraform-provider-akamai/v2/pkg/akamai" @@ -57,25 +58,43 @@ func resourceWAFProtectionRead(ctx context.Context, d *schema.ResourceData, m in logger := meta.Log("APPSEC", "resourceWAFProtectionRead") getWAFProtection := appsec.GetWAFProtectionRequest{} + if d.Id() != "" && strings.Contains(d.Id(), ":") { + s := strings.Split(d.Id(), ":") - configid, err := tools.GetIntValue("config_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFProtection.ConfigID = configid + configid, errconv := strconv.Atoi(s[0]) + if errconv != nil { + return diag.FromErr(errconv) + } + getWAFProtection.ConfigID = configid - version, err := tools.GetIntValue("version", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFProtection.Version = version + version, errconv := strconv.Atoi(s[1]) + if errconv != nil { + return diag.FromErr(errconv) + } + getWAFProtection.Version = version - policyid, err := tools.GetStringValue("security_policy_id", d) - if err != nil && !errors.Is(err, tools.ErrNotFound) { - return diag.FromErr(err) - } - getWAFProtection.PolicyID = policyid + policyid := s[2] + getWAFProtection.PolicyID = policyid + + } else { + configid, err := tools.GetIntValue("config_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFProtection.ConfigID = configid + version, err := tools.GetIntValue("version", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFProtection.Version = version + + policyid, err := tools.GetStringValue("security_policy_id", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return diag.FromErr(err) + } + getWAFProtection.PolicyID = policyid + } wafprotection, err := client.GetWAFProtection(ctx, getWAFProtection) if err != nil { logger.Errorf("calling 'getWAFProtection': %s", err.Error()) @@ -92,7 +111,19 @@ func resourceWAFProtectionRead(ctx context.Context, d *schema.ResourceData, m in } } - d.SetId(strconv.Itoa(getWAFProtection.ConfigID)) + if err := d.Set("config_id", getWAFProtection.ConfigID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("version", getWAFProtection.Version); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + if err := d.Set("security_policy_id", getWAFProtection.PolicyID); err != nil { + return diag.FromErr(fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error())) + } + + d.SetId(fmt.Sprintf("%d:%d:%s", getWAFProtection.ConfigID, getWAFProtection.Version, getWAFProtection.PolicyID)) return nil } diff --git a/pkg/providers/appsec/resource_akamai_appsec_waf_protection_test.go b/pkg/providers/appsec/resource_akamai_appsec_waf_protection_test.go index d36c9a615..6d6f0f9d7 100644 --- a/pkg/providers/appsec/resource_akamai_appsec_waf_protection_test.go +++ b/pkg/providers/appsec/resource_akamai_appsec_waf_protection_test.go @@ -39,7 +39,7 @@ func TestAccAkamaiWAFProtection_res_basic(t *testing.T) { { Config: loadFixtureString("testdata/TestResWAFProtection/match_by_id.tf"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("akamai_appsec_waf_protection.test", "id", "43253"), + resource.TestCheckResourceAttr("akamai_appsec_waf_protection.test", "id", "43253:7:AAAA_81230"), ), }, }, diff --git a/pkg/providers/appsec/templates.go b/pkg/providers/appsec/templates.go index f434e8325..ad69fae84 100644 --- a/pkg/providers/appsec/templates.go +++ b/pkg/providers/appsec/templates.go @@ -2,6 +2,7 @@ package appsec import ( "bytes" + "encoding/json" "fmt" "strconv" "strings" @@ -37,6 +38,10 @@ func RenderTemplates(ots map[string]*OutputTemplate, key string, str interface{} funcs = template.FuncMap{ "join": strings.Join, "quote": func(in string) string { return fmt.Sprintf("\"%s\"", in) }, + "marshal": func(v interface{}) string { + a, _ := json.Marshal(v) + return string(a) + }, "dash": func(in int) string { if in == 0 { return "-" @@ -44,6 +49,27 @@ func RenderTemplates(ots map[string]*OutputTemplate, key string, str interface{} return strconv.Itoa(in) } }, + + "substring": func(start, end int, s string) string { + if start < 0 { + return s[:end] + } + if end < 0 || end > len(s) { + return s[start:] + } + return s[start:end] + }, + + "splitprefix": func(sep, orig string) map[string]string { + parts := strings.Split(orig, sep) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res + }, + + "replace": func(old, new, src string) string { return strings.Replace(src, old, new, -1) }, } ) @@ -90,9 +116,23 @@ func RenderTemplates(ots map[string]*OutputTemplate, key string, str interface{} } func InitTemplates(otm map[string]*OutputTemplate) { - + otm["advancedSettingsLoggingDS"] = &OutputTemplate{TemplateName: "advancedSettingsLoggingDS", TableTitle: "Allow Sampling|Cookies|Custom Headers|Standard Headers", TemplateType: "TABULAR", TemplateString: "{{.AllowSampling}}|{{.Cookies.Type}} {{.Cookies.Values}}|{{.CustomHeaders.Type}} {{.CustomHeaders.Values}}|{{.StandardHeaders.Type}} {{.StandardHeaders.Values}}"} + otm["advancedSettingsPrefetchDS"] = &OutputTemplate{TemplateName: "advancedSettingsPrefetchDS", TableTitle: "Enable App Layer|All Extension|Enable Rate Controls|Extensions", TemplateType: "TABULAR", TemplateString: "{{.EnableAppLayer}}|{{.AllExtensions}}|{{.EnableRateControls}}|{{range $index, $element := .Extensions}}{{.}} {{end}}"} + otm["apiHostnameCoverageMatchTargetsDS"] = &OutputTemplate{TemplateName: "apiHostnameCoverageMatchTargetsDS", TableTitle: "Hostnames|Target ID|Type", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .MatchTargets.WebsiteTargets}}{{if $index}},{{end}}{{.Hostnames}}|{{.TargetID}}|{{.Type}}{{end}}"} + otm["apiHostnameCoverageoverLappingDS"] = &OutputTemplate{TemplateName: "apiHostnameCoverageoverLappingDS", TableTitle: "ID|Name|Version|Contract ID|Contract Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .OverLappingList}}{{if $index}},{{end}}{{.ConfigID}}|{{.ConfigName}}|{{.ConfigVersion}}|{{.ContractID}}|{{.ContractName}}{{end}}"} + + //Extensions + otm["apiEndpointsDS"] = &OutputTemplate{TemplateName: "apiEndpointsDS", TableTitle: "ID|Endpoint Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .APIEndpoints}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} + otm["AttackGroupConditionException"] = &OutputTemplate{TemplateName: "AttackGroupConditionException", TableTitle: "Conditions|Exceptions|Advanced Exceptions", TemplateType: "TABULAR", TemplateString: "{{$length := len .AdvancedExceptionsList.Conditions}}{{ if eq $length 0 }}False{{else}}True{{end}}|{{if .Exception}}True{{else}}False{{end}}|{{if .AdvancedExceptionsList }}True{{else}}False{{end}}"} + + otm["policyApiEndpointsDS"] = &OutputTemplate{TemplateName: "policyApiEndpointsDS", TableTitle: "ID|Endpoint Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .APIEndpoints}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} + otm["apiHostnameCoverageDS"] = &OutputTemplate{TemplateName: "apiHostnameCoverageDS", TableTitle: "Config ID|Config Name|Version|Status|Has Match Target|Hostname", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .HostnameCoverage}}{{if $index}},{{end}}{{.Configuration.ID}}|{{.Configuration.Name}}|{{.Configuration.Version}}|{{.Status}}|{{.HasMatchTarget}}|{{.Hostname}}{{end}}"} + otm["apiRequestConstraintsDS"] = &OutputTemplate{TemplateName: "apiRequestConstraintsDS", TableTitle: "ID|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .APIEndpoints}}{{if $index}},{{end}}{{.ID}}|{{.Action}}{{end}}"} otm["configuration"] = &OutputTemplate{TemplateName: "Configurations", TableTitle: "Config_id|Name|Latest_version|Version_active_in_staging|Version_active_in_production", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .Configurations}}{{if $index}},{{end}}{{.ID}}|{{.Name}}|{{.LatestVersion}}|{{.StagingVersion}}|{{.ProductionVersion}}{{end}}"} otm["configurationVersion"] = &OutputTemplate{TemplateName: "ConfigurationVersion", TableTitle: "Version Number|Staging Status|Production Status", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .VersionList}}{{if $index}},{{end}}{{.Version}}|{{.Staging.Status}}|{{.Production.Status}}{{end}}"} + otm["contractsgroupsDS"] = &OutputTemplate{TemplateName: "contractsgroupsDS", TableTitle: "ContractID|GroupID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .ContractGroups}}{{if $index}},{{end}}{{.ContractID}}|{{.GroupID}}|{{.DisplayName}}{{end}}"} + otm["failoverHostnamesDS"] = &OutputTemplate{TemplateName: "failoverHostnamesDS", TableTitle: "Hostname", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .HostnameList}}{{if $index}},{{end}}{{.Hostname}}{{end}}"} + otm["bypassNetworkListsDS"] = &OutputTemplate{TemplateName: "bypassNetworkListsDS", TableTitle: "Network List|ID", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .NetworkLists}}{{if $index}},{{end}}{{.Name}}|{{.ID}}{{end}}"} otm["penaltyBoxDS"] = &OutputTemplate{TemplateName: "penaltyBoxDS", TableTitle: "PenaltyBoxProtection|Action", TemplateType: "TABULAR", TemplateString: "{{.PenaltyBoxProtection}}|{{.Action}}"} @@ -100,24 +140,28 @@ func InitTemplates(otm map[string]*OutputTemplate) { otm["selectableHostsDS"] = &OutputTemplate{TemplateName: "selectableHosts", TableTitle: "Hostname|ConfigIDInProduction|ConfigNameInProduction", TemplateType: "TABULAR", TemplateString: "{{range .AvailableSet}}{{.Hostname}}|{{ dash .ConfigIDInProduction }}|{{.ConfigNameInProduction}},{{end}}"} otm["selectedHosts"] = &OutputTemplate{TemplateName: "selectedHosts", TableTitle: "Hostnames", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .SelectedHosts}}{{if $index}},{{end}}{{.}}{{end}}"} otm["selectedHostsDS"] = &OutputTemplate{TemplateName: "selectedHosts", TableTitle: "Hostnames", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .HostnameList}}{{if $index}},{{end}}{{.Hostname}}{{end}}"} - otm["selectedHosts.tf"] = &OutputTemplate{TemplateName: "selectedHosts.tf", TableTitle: "Hostname", TemplateType: "TERRAFORM", TemplateString: "\nresource \"akamai_appsec_selected_hostnames\" \"appsecselectedhostnames\" { \n config_id = {{.ConfigID}}\n version = {{.Version}}\n hostnames = [{{ range $index, $element := .SelectedHosts }}{{if $index}},{{end}}{{quote .}}{{end}}] \n }"} + otm["siemsettingsDS"] = &OutputTemplate{TemplateName: "siemsettingsDS", TableTitle: "Enable For All Policies|Enable Siem|Enabled Botman Siem Events|Siem Definition ID|FirewallPolicyIds", TemplateType: "TABULAR", TemplateString: "{{.EnableForAllPolicies}}|{{.EnableSiem}}|{{.EnabledBotmanSiemEvents}}|{{.SiemDefinitionID}}|{{.FirewallPolicyIds}}"} + otm["siemDefinitionsDS"] = &OutputTemplate{TemplateName: "siemDefinitionsDS", TableTitle: "ID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .SiemDefinitions}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} + otm["ratePolicies"] = &OutputTemplate{TemplateName: "ratePolicies", TableTitle: "ID|Policy Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .RatePolicies}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} otm["matchTargets"] = &OutputTemplate{TemplateName: "matchTargets", TableTitle: "ID|PolicyID", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .MatchTargets.WebsiteTargets}}{{if $index}},{{end}}{{.ID}}|{{.SecurityPolicy.PolicyID}}{{end}}"} otm["matchTargetDS"] = &OutputTemplate{TemplateName: "matchTarget", TableTitle: "ID|PolicyID", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .MatchTargets.WebsiteTargets}}{{if $index}},{{end}}{{.TargetID}}|{{.SecurityPolicy.PolicyID}}{{end}}"} otm["reputationProfiles"] = &OutputTemplate{TemplateName: "reputationProfiles", TableTitle: "ID|Name(Title)", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .ReputationProfiles}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} + otm["reputationAnalysisDS"] = &OutputTemplate{TemplateName: "reputationAnalysisDS", TableTitle: "forwardToHTTPHeader|forwardSharedIPToHTTPHeaderAndSIEM", TemplateType: "TABULAR", TemplateString: "{{.ForwardToHTTPHeader}}|{{.ForwardSharedIPToHTTPHeaderAndSIEM}}"} otm["reputationProfilesDS"] = &OutputTemplate{TemplateName: "reputationProfilesDS", TableTitle: "ID|Name(Title)", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .ReputationProfiles}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} otm["reputationProfilesActions"] = &OutputTemplate{TemplateName: "reputationProfilesActions", TableTitle: "ID|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .ReputationProfiles}}{{if $index}},{{end}}{{.ID}}| {{.Action}}{{end}}"} otm["customRules"] = &OutputTemplate{TemplateName: "customRules", TableTitle: "ID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .CustomRules}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} + otm["customDenyDS"] = &OutputTemplate{TemplateName: "customDenyDS", TableTitle: "ID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .CustomDenyList}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} otm["customRuleActions"] = &OutputTemplate{TemplateName: "customRuleActions", TableTitle: "ID|Action", TemplateType: "TABULAR", TemplateString: "{{range .SecurityPolicies}}{{range $index, $element := .CustomRuleActions}}{{if $index}},{{end}}{{.ID}}|{{.Action}}{{end}}{{end}}"} otm["customRuleAction"] = &OutputTemplate{TemplateName: "customRuleAction", TableTitle: "ID|Name|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .}}{{if $index}},{{end}}{{.RuleID}}|{{.Name}} |{{.Action}}{{end}}"} otm["ratePolicyActions"] = &OutputTemplate{TemplateName: "ratePolicyActions", TableTitle: "ID|Ipv4Action|Ipv6Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .RatePolicyActions}}{{if $index}},{{end}}{{.ID}}| {{.Ipv4Action}}|{{.Ipv6Action}}{{end}}"} otm["RulesDS"] = &OutputTemplate{TemplateName: "RulesDS", TableTitle: "ID|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .RuleActions}}{{if $index}},{{end}}{{.ID}}|{{.Action}}{{end}}"} otm["EvalRulesActionsDS"] = &OutputTemplate{TemplateName: "evalRulesActions", TableTitle: "ID|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .RuleActions}}{{if $index}},{{end}}{{.ID}}| {{.Action}}{{end}}"} - - otm["rulesets"] = &OutputTemplate{TemplateName: "rulesets", TableTitle: "ID|Name(Title)", TemplateType: "TABULAR", TemplateString: "{{range .Rulesets}}{{range $index, $element := .Rules}}{{if $index}},{{end}}{{.ID}}| {{.Title}}{{end}}{{end}}"} + otm["evalHostnamesDS"] = &OutputTemplate{TemplateName: "evalHostnamesDS", TableTitle: "Hostnames", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .Hostnames}}{{if $index}},{{end}}{{.}}{{end}}"} + otm["rulesets"] = &OutputTemplate{TemplateName: "rulesets", TableTitle: "ID|Name(Title)", TemplateType: "TABULAR", TemplateString: "{{range .Rulesets}}{{range $index, $element := .Rules}}{{if $index}},{{end}}{{.ID}}| {{substring 0 45 .Title}}{{end}}{{end}}"} otm["securityPolicies"] = &OutputTemplate{TemplateName: "securityPolicies", TableTitle: "ID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .SecurityPolicies}}{{if $index}},{{end}}{{.ID}}|{{.Name}}{{end}}"} otm["securityPoliciesDS"] = &OutputTemplate{TemplateName: "securityPolicies", TableTitle: "ID|Name", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .Policies}}{{if $index}},{{end}}{{.PolicyID}}|{{.PolicyName}}{{end}}"} @@ -125,11 +169,43 @@ func InitTemplates(otm map[string]*OutputTemplate) { otm["slowPostDS"] = &OutputTemplate{TemplateName: "slowPost", TableTitle: "Action|SLOW_RATE_THRESHOLD RATE|SLOW_RATE_THRESHOLD PERIOD|DURATION_THRESHOLD TIMEOUT", TemplateType: "TABULAR", TemplateString: "{{.Action}}|{{.SlowRateThreshold.Rate}}|{{.SlowRateThreshold.Period}}|{{.DurationThreshold.Timeout}}"} otm["slowPost"] = &OutputTemplate{TemplateName: "slowPost", TableTitle: "Action|SLOW_RATE_THRESHOLD RATE|SLOW_RATE_THRESHOLD PERIOD|DURATION_THRESHOLD TIMEOUT", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .SecurityPolicies}}{{if $index}},{{end}}{{.SlowPost.Action}}|{{.SlowPost.DurationThreshold.Timeout}}|{{.SlowPost.SlowRateThreshold.Rate}}|{{.SlowPost.SlowRateThreshold.Period}}{{end}}"} otm["wafModesDS"] = &OutputTemplate{TemplateName: "wafMode", TableTitle: "Current|Mode|Eval", TemplateType: "TABULAR", TemplateString: "{{.Current}}|{{.Mode}}|{{.Eval}}"} + otm["versionNotesDS"] = &OutputTemplate{TemplateName: "versionNotesDS", TableTitle: "Version Notes", TemplateType: "TABULAR", TemplateString: "{{.Notes}}"} otm["wafProtectionDS"] = &OutputTemplate{TemplateName: "wafProtection", TableTitle: "APIConstraints|ApplicationLayerControls|BotmanControls|NetworkLayerControls|RateControls|ReputationControls|SlowPostControls", TemplateType: "TABULAR", TemplateString: "{{.ApplyAPIConstraints}}|{{.ApplyApplicationLayerControls}}|{{.ApplyBotmanControls}}|{{.ApplyNetworkLayerControls}}|{{.ApplyRateControls}}|{{.ApplyReputationControls}}|{{.ApplySlowPostControls}}"} otm["AttackGroupActionDS"] = &OutputTemplate{TemplateName: "AttackGroupAction", TableTitle: "GroupID|Action", TemplateType: "TABULAR", TemplateString: "{{range $index, $element := .AttackGroupActions}}{{if $index}},{{end}}{{.Group}}| {{.Action}}{{end}}"} otm["rateProtectionDS"] = &OutputTemplate{TemplateName: "rateProtection", TableTitle: "APIConstraints|ApplicationLayerControls|BotmanControls|NetworkLayerControls|RateControls|ReputationControls|SlowPostControls", TemplateType: "TABULAR", TemplateString: "{{.ApplyAPIConstraints}}|{{.ApplyApplicationLayerControls}}|{{.ApplyBotmanControls}}|{{.ApplyNetworkLayerControls}}|{{.ApplyRateControls}}|{{.ApplyReputationControls}}|{{.ApplySlowPostControls}}"} otm["reputationProtectionDS"] = &OutputTemplate{TemplateName: "reputationProtection", TableTitle: "APIConstraints|ApplicationLayerControls|BotmanControls|NetworkLayerControls|RateControls|ReputationControls|SlowPostControls", TemplateType: "TABULAR", TemplateString: "{{.ApplyAPIConstraints}}|{{.ApplyApplicationLayerControls}}|{{.ApplyBotmanControls}}|{{.ApplyNetworkLayerControls}}|{{.ApplyRateControls}}|{{.ApplyReputationControls}}|{{.ApplySlowPostControls}}"} otm["slowpostProtectionDS"] = &OutputTemplate{TemplateName: "slowpostProtection", TableTitle: "APIConstraints|ApplicationLayerControls|BotmanControls|NetworkLayerControls|RateControls|ReputationControls|SlowPostControls", TemplateType: "TABULAR", TemplateString: "{{.ApplyAPIConstraints}}|{{.ApplyApplicationLayerControls}}|{{.ApplyBotmanControls}}|{{.ApplyNetworkLayerControls}}|{{.ApplyRateControls}}|{{.ApplyReputationControls}}|{{.ApplySlowPostControls}}"} - otm["RuleConditionException"] = &OutputTemplate{TemplateName: "RuleConditionException", TableTitle: "Conditions|Exceptions", TemplateType: "TABULAR", TemplateString: "{{range $index, $element :=.Conditions}}True{{else}}False{{end}}|{{with .Exception}}True{{else}}False{{end}}"} + + otm["RuleConditionException"] = &OutputTemplate{TemplateName: "RuleConditionException", TableTitle: "Conditions|Exceptions", TemplateType: "TABULAR", TemplateString: "{{if .Conditions}}True{{else}}False{{end}}|{{if .Exception}}True{{else}}False{{end}}"} + + // TF templates + otm["AdvancedSettingsLogging.tf"] = &OutputTemplate{TemplateName: "AdvancedSettingsLogging.tf", TableTitle: "AdvancedSettingsLogging", TemplateType: "TERRAFORM", TemplateString: "\nresource \"akamai_appsec_advanced_settings_logging\" \"akamai_appsec_advanced_settings_logging\" { \n config_id = {{.ConfigID}}\n version = {{.Version}}\n logging = <<-EOF\n {{marshal .AdvancedOptions.Logging}} \n EOF \n } \n {{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range $index1, $element := .SecurityPolicies}}{{$prev_secpolicy := .ID}}{{if .LoggingOverrides}}\nresource \"akamai_appsec_advanced_settings_logging\" \"akamai_appsec_advanced_settings_logging_override{{if $index1}}_{{$index1}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n logging = <<-EOF\n {{marshal .LoggingOverrides}} \n \n EOF \n \n }\n{{end}} {{end}}"} + + otm["AdvancedSettingsPrefetch.tf"] = &OutputTemplate{TemplateName: "AdvancedSettingsPrefetch.tf", TableTitle: "AdvancedSettingsPrefetch", TemplateType: "TERRAFORM", TemplateString: "\nresource \"akamai_appsec_advanced_settings_prefetch\" \"akamai_appsec_advanced_settings_prefetch\" { \n config_id = {{.ConfigID}}\n version = {{.Version}}\n enable_app_layer = {{.AdvancedOptions.Prefetch.EnableAppLayer}} \n all_extensions = {{.AdvancedOptions.Prefetch.AllExtensions}}\n enable_rate_controls = {{.AdvancedOptions.Prefetch.EnableRateControls}}\n extensions = [{{ range $index, $element := .AdvancedOptions.Prefetch.Extensions }}{{if $index}},{{end}}{{quote .}}{{end}}] \n } \n"} + otm["ApiRequestConstraints.tf"] = &OutputTemplate{TemplateName: "ApiRequestConstraints.tf", TableTitle: "ApiRequestConstraints", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range $index1, $element := .SecurityPolicies}}{{$prev_secpolicy := .ID}}{{if .APIRequestConstraints.Action}}\nresource \"akamai_appsec_api_request_constraints\" \"api_request_constraints_{{$prev_secpolicy}}{{if $index1}}_{{$index1}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n action = \"{{.APIRequestConstraints.Action}}\" \n }{{end}}\n {{range $index, $element := .APIRequestConstraints.APIEndpoints}}\nresource \"akamai_appsec_api_request_constraints\" \"api_request_constraints_override_{{.ID}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n api_endpoint_id = \"{{.ID}}\" \n action = \"{{.Action}}\" \n }\n{{end}}{{end}}"} + otm["AttackGroupAction.tf"] = &OutputTemplate{TemplateName: "AttackGroupAction.tf", TableTitle: "AttackGroupAction", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.AttackGroupActions}}\nresource \"akamai_appsec_attack_group_action\" \"akamai_appsec_attack_group_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n attack_group = \"{{.Group}}\" \n attack_group_action = \"{{.Action}}\" \n }\n{{end}}{{end}}"} + otm["AttackGroupConditionException.tf"] = &OutputTemplate{TemplateName: "AttackGroupConditionException.tf", TableTitle: "AttackGroupConditionException", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.AttackGroupActions}}{{ if or .AdvancedExceptions .Exception}}\nresource \"akamai_appsec_attack_group_condition_exception\" \"akamai_appsec_attack_group_condition_exception_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n attack_group = \"{{.Group}}\" \n condition_exception = <<-EOF\n {{marshal .}} \n \n EOF \n \n }\n{{end}}{{end}}{{end}}"} + + otm["EvalAction.tf"] = &OutputTemplate{TemplateName: "EvalActions.tf", TableTitle: "EvalActions", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.Evaluation.RuleActions}}\nresource \"akamai_appsec_eval_rule_action\" \"akamai_appsec_eval_rule_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n rule_id = {{.ID}} \n rule_action = \"{{.Action}}\" \n }\n{{end}}{{end}}"} + otm["EvalRuleConditionException.tf"] = &OutputTemplate{TemplateName: "EvalRuleConditionException.tf", TableTitle: "EvalRuleConditionException", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.Evaluation.RuleActions}}{{ if or .Conditions .Exception}}\nresource \"akamai_appsec_eval_rule_condition_exception\" \"akamai_appsec_eval_rule_condition_exception_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n rule_id = {{.ID}} \n condition_exception = <<-EOF\n {{marshal .}} \n \n EOF \n \n }\n{{end}}{{end}}{{end}}"} + + otm["CustomDeny.tf"] = &OutputTemplate{TemplateName: "CustomDeny.tf", TableTitle: "CustomDeny", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{range $index, $element := .CustomDenyList}}\nresource \"akamai_appsec_custom_deny\" \"akamai_appsec_custom_deny{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config }}\n version = {{ $version }}\n custom_deny = <<-EOF\n {{marshal .}} \n EOF \n \n }\n{{end}}"} + otm["CustomRule.tf"] = &OutputTemplate{TemplateName: "CustomRule.tf", TableTitle: "CustomRule", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{range $index, $element := .CustomRules}} \nresource \"akamai_appsec_custom_rule\" \"akamai_appsec_custom_rule{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n custom_rule = <<-EOF\n {{marshal .}} \n EOF \n }\n {{end}}"} + otm["CustomRuleAction.tf"] = &OutputTemplate{TemplateName: "CustomRuleAction.tf", TableTitle: "CustomRuleAction", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{ range $index, $element := .SecurityPolicies }}{{$prev_secpolicy:=$element.ID}} {{ range $index, $element := .CustomRuleActions }} \nresource \"akamai_appsec_custom_rule_action\" \"akamai_appsec_custom_rule_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n custom_rule_id = {{.ID}} \n custom_rule_action = \"{{.Action}}\" \n } \n {{end}}{{end}}"} + otm["MatchTarget.tf"] = &OutputTemplate{TemplateName: "MatchTarget.tf", TableTitle: "MatchTarget", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{range $index, $element := .MatchTargets.WebsiteTargets}}\nresource \"akamai_appsec_match_target\" \"akamai_appsec_match_target_{{.ID}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n match_target = <<-EOF\n {{marshal .}} \n EOF \n }\n {{end}}\n {{range $index, $element := .MatchTargets.APITargets}}\nresource \"akamai_appsec_match_target\" \"akamai_appsec_match_target_{{.ID}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n match_target = <<-EOF\n {{marshal .}} \n EOF \n }\n {{end}}"} + otm["PenaltyBox.tf"] = &OutputTemplate{TemplateName: "PenaltyBox.tf", TableTitle: "PenaltyBox", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range $index, $element := .SecurityPolicies}}{{$prev_secpolicy := .ID}}{{if .PenaltyBox.Action}} \nresource \"akamai_appsec_penalty_box\" \"akamai_appsec_penalty_box_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config }}\n version = {{ $version }}\n security_policy_id = \"{{$prev_secpolicy}}\" \n penalty_box_protection = \"{{.PenaltyBox.PenaltyBoxProtection}}\" \n penalty_box_action = \"{{.PenaltyBox.Action}}\" \n}\n{{end}}{{end}}"} + otm["RatePolicy.tf"] = &OutputTemplate{TemplateName: "RatePolicy.tf", TableTitle: "RatePolicy", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{range $index, $element := .RatePolicies}}\nresource \"akamai_appsec_rate_policy\" \"akamai_appsec_rate_policy{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config }}\n version = {{ $version }}\n rate_policy = <<-EOF\n {{marshal .}} \n EOF \n \n }\n{{end}}"} + otm["RatePolicyAction.tf"] = &OutputTemplate{TemplateName: "RatePolicyAction.tf", TableTitle: "RatePolicyAction", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{ range $index, $element := .RatePolicyActions }}\nresource \"akamai_appsec_rate_policy_action\" \"akamai_appsec_rate_policy_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}}\n security_policy_id = \"{{$prev_secpolicy}}\" \n rate_policy_id = {{.ID}} \n ipv4_action = \"{{.Ipv4Action}}\" \n ipv6_action = \"{{.Ipv6Action}}\" \n }\n {{end}} {{end}}"} + otm["ReputationProfile.tf"] = &OutputTemplate{TemplateName: "ReputationProfile.tf", TableTitle: "ReputationProfile", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{range $index, $element := .ReputationProfiles}}\nresource \"akamai_appsec_reputation_profile\" \"akamai_appsec_reputation_profile{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config}}\n version = {{ $version }}\n reputation_profile = <<-EOF\n {{marshal .}} \n \n EOF \n }{{end}}"} + otm["ReputationProfileAction.tf"] = &OutputTemplate{TemplateName: "ReputationProfileAction.tf", TableTitle: "ReputationProfileAction", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .ClientReputation.ReputationProfileActions}}\nresource \"akamai_appsec_reputation_profile_action\" \"akamai_appsec_reputation_profile_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config }}\n version = {{ $version }}\n security_policy_id = \"{{$prev_secpolicy}}\" \n reputation_profile_id = \"{{.Action}}\" \n }\n{{end}}{{end}}"} + otm["RuleAction.tf"] = &OutputTemplate{TemplateName: "RuleAction.tf", TableTitle: "RuleAction", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.RuleActions}}\nresource \"akamai_appsec_rule_action\" \"akamai_appsec_rule_action_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}} \n security_policy_id = \"{{$prev_secpolicy}}\" \n rule_id = {{.ID}} \n rule_action = \"{{.Action}}\" \n }\n{{end}}{{end}}"} + otm["RuleConditionException.tf"] = &OutputTemplate{TemplateName: "RuleConditionException.tf", TableTitle: "RuleConditionException", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}} {{range $index, $element := .WebApplicationFirewall.RuleActions}}{{ if or .Conditions .Exception }}\nresource \"akamai_appsec_rule_condition_exception\" \"akamai_appsec_condition_exception_{{$prev_secpolicy}}{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{$config}}\n version = {{$version}} \n security_policy_id = \"{{$prev_secpolicy}}\" \n rule_id = {{.ID}} \n condition_exception = <<-EOF\n {{marshal .}} \n \n EOF \n \n }\n{{end}}{{end}}{{end}}"} + + otm["SecurityPolicy.tf"] = &OutputTemplate{TemplateName: "SecurityPolicy.tf", TableTitle: "SecurityPolicy", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{ $spx := \"\" }} {{range $index, $element := .SecurityPolicies}}{{$prev_secpolicy := .ID}}{{ $spx := splitprefix \"_\" .ID}} \nresource \"akamai_appsec_security_policy\" \"akamai_appsec_security_policy{{if $index}}_{{$index}}{{end}}\" { \n config_id = {{ $config }}\n version = {{ $version }}\n security_policy_name = \"{{.Name}}\" \n security_policy_prefix = \"{{$spx._0}}\" \n default_settings = true \n }\n{{end}}"} + otm["SelectedHostname.tf"] = &OutputTemplate{TemplateName: "SelectedHostname.tf", TableTitle: "SelectedHostname", TemplateType: "TERRAFORM", TemplateString: "\nresource \"akamai_appsec_selected_hostnames\" \"akamai_appsec_selected_hostname\" { \n config_id = {{.ConfigID}}\n version = {{.Version}}\n mode = \"REPLACE\" \n hostnames = [{{ range $index, $element := .SelectedHosts }}{{if $index}},{{end}}{{quote .}}{{end}}] \n }"} + otm["SiemSettings.tf"] = &OutputTemplate{TemplateName: "SiemSettings.tf", TableTitle: "SiemSettings", TemplateType: "TERRAFORM", TemplateString: "\nresource \"akamai_appsec_siem_settings\" \"siem_settings\" { \n config_id = {{.ConfigID}}\n version = {{.Version}}\n enable_siem = {{.Siem.EnableSiem}} \n enable_for_all_policies = {{.Siem.EnableForAllPolicies}}\n enable_botman_siem = {{.Siem.EnabledBotmanSiemEvents}}\n siem_id = {{.Siem.SiemDefinitionID}}\n security_policy_ids = [{{ range $index, $element := .Siem.FirewallPolicyIds}}{{if $index}},{{end}}{{quote .}}{{end}}] \n \n } \n"} + otm["SlowPost.tf"] = &OutputTemplate{TemplateName: "SlowPost.tf", TableTitle: "SlowPost", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}}\nresource \"akamai_appsec_slow_post\" \"akamai_appsec_slow_post_{{$prev_secpolicy}}\" { \n config_id = {{$config}}\n version = {{$version}} \n security_policy_id = \"{{$prev_secpolicy}}\" \n slow_rate_action = \"{{.SlowPost.Action}}\" \n slow_rate_threshold_rate = {{.SlowPost.SlowRateThreshold.Rate}}\n slow_rate_threshold_period = {{.SlowPost.SlowRateThreshold.Period}}\n duration_threshold_timeout = {{.SlowPost.DurationThreshold.Timeout}}\n \n } \n{{end}}"} + otm["IPGeoFirewall.tf"] = &OutputTemplate{TemplateName: "IPGeoFirewall.tf", TableTitle: "IPGeoFirewall", TemplateType: "TERRAFORM", TemplateString: "{{ $config := .ConfigID }}{{ $version := .Version }}{{ $prev_secpolicy := \"\" }}{{range .SecurityPolicies}}{{$prev_secpolicy := .ID}}\nresource \"akamai_appsec_ip_geo\" \"akamai_appsec_ip_geo_{{$prev_secpolicy}}\" { \n config_id = {{$config}}\n version = {{$version}} \n security_policy_id = \"{{$prev_secpolicy}}\" \n mode = {{if eq .IPGeoFirewall.Block \"blockSpecificIPGeo\"}}\"block\"{{else}}\"allow\"{{end}} \n geo_network_lists = [{{ range $index, $element := .IPGeoFirewall.GeoControls.BlockedIPNetworkLists.NetworkList }}{{if $index}},{{end}}{{quote .}}{{end}}]\n ip_network_lists = [{{ range $index, $element := .IPGeoFirewall.IPControls.BlockedIPNetworkLists.NetworkList }}{{if $index}},{{end}}{{quote .}}{{end}}]\n exception_ip_network_lists = [{{ range $index, $element := .IPGeoFirewall.IPControls.AllowedIPNetworkLists.NetworkList }}{{if $index}},{{end}}{{quote .}}{{end}}] \n \n } \n{{end}}"} + } diff --git a/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/AdvancedSettingsLogging.json b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/AdvancedSettingsLogging.json new file mode 100644 index 000000000..e9c621f1e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/AdvancedSettingsLogging.json @@ -0,0 +1,14 @@ +[ + { + "allowSampling": true, + "cookies": { + "type": "all" + }, + "customHeaders": { + "type": "all" + }, + "standardHeaders": { + "type": "all" + } + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/match_by_id.tf new file mode 100644 index 000000000..b13641f04 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsLogging/match_by_id.tf @@ -0,0 +1,10 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_advanced_settings_logging" "test" { + config_id = 43253 + version = 7 + +} + diff --git a/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json new file mode 100644 index 000000000..9192268f4 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json @@ -0,0 +1,37 @@ + + { + "attackGroupActions": [ + { + "action": "none", + "group": "TOOL" + }, + { + "action": "none", + "group": "PROTOCOL" + }, + { + "action": "none", + "group": "SQL" + }, + { + "action": "none", + "group": "XSS" + }, + { + "action": "none", + "group": "LFI" + }, + { + "action": "none", + "group": "RFI" + }, + { + "action": "none", + "group": "CMDI" + }, + { + "action": "none", + "group": "PLATFORM" + } + ] + } diff --git a/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/match_by_id.tf new file mode 100644 index 000000000..4c8496f5d --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSAdvancedSettingsPrefetch/match_by_id.tf @@ -0,0 +1,9 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +data "akamai_appsec_advanced_settings_prefetch" "test" { + config_id = 43253 + version = 7 +} diff --git a/pkg/providers/appsec/testdata/TestDSApiEndpoints/ApiEndpoints.json b/pkg/providers/appsec/testdata/TestDSApiEndpoints/ApiEndpoints.json new file mode 100644 index 000000000..5149290d6 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiEndpoints/ApiEndpoints.json @@ -0,0 +1,38 @@ +{ + "apiEndpoints": [ + { + "id": 619183, + "name": "Orders", + "basePath": "/v1/orders", + "apiEndPointHosts": [ + "sg.akamai.com" + ], + "stagingVersion": { + "status": "ACTIVE", + "versionNumber": 1 + }, + "productionVersion": { + "status": "ACTIVE", + "versionNumber": 1 + }, + "requestConstraintsEnabled": false + }, + { + "id": 624913, + "name": "Catalog", + "basePath": "/v1/catalog", + "apiEndPointHosts": [ + "sg.akamai.com" + ], + "stagingVersion": { + "status": "ACTIVE", + "versionNumber": 1 + }, + "productionVersion": { + "status": "ACTIVE", + "versionNumber": 1 + }, + "requestConstraintsEnabled": true + } + ] +} diff --git a/pkg/providers/appsec/testdata/TestDSApiEndpoints/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSApiEndpoints/match_by_id.tf new file mode 100644 index 000000000..d6ae33320 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiEndpoints/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + + +data "akamai_appsec_api_endpoints" "test" { + config_id = 43253 + version = 7 + + // api_name = var.api_endpoint_name +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/ApiHostnameCoverage.json b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/ApiHostnameCoverage.json new file mode 100644 index 000000000..02b524ef4 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/ApiHostnameCoverage.json @@ -0,0 +1,1938 @@ + + { + "hostnameCoverage": [ + { + "hasMatchTarget": false, + "hostname": "interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "arm.slackware.com", + "policyNames": [ + "Slackware Sites" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.350.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "rbaraut.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "fareportal-fppowerhotelxml.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "daveyshafik.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.schan-sf.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "2.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "captainakamai-insecure.captainwhite.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "apitest1.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "philipbrown.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "bfrancisproperty.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "anblanco.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.priyankasharma-delhi.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.canipush.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "gmt-demo.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "nverkland.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kweechuan.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.tvaliji-london.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kimmich.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.kirsten.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "s1.daveyshafik.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static.hk.zalora.net.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*-msltest-lh.akamaihd.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ipa.akamaitools.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "mjaganna.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "nael.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api.irresistibleapis.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.iahmed-yyz.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "www.colinbendell.com", + "policyNames": [ + "Bot" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "jakebr.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "data.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "imoppty.akam.ai", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edge2017-jramer.www.wp1.akamaiuweb.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "biscuit.org.uk.edgesuite.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.leokimseoul.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.aevans-seattle.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "yoav.ws", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.ezhang-sydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "rgamoji.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jennip.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "stage-www.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.261.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "prod.config-as-code.web.astronaut.training", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dereka.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "180125johnh.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "openapidemo.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static.urbancrawlapp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "*.colinbendell.com", + "policyNames": [ + "Bot" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "h1cwnd24.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "sjevsejev.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.liquidmatrix.org", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kirsten.im.edgesuite.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "4.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "shouldipush.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.dquintero.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "push-ext.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "base-template.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "gtm-demo.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "lawlait.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.jthur-ams.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "fst.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api.urbancrawlapp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "im-florist.akamaiflowershop.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test68.randomnoise.us", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "golang.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.bmt-shtakuma.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "justogusto1212.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.westest-waterloo.world-tour.akamaidevveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.geekgonenomad.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tp7.utkarshgoel.in", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.aviso-madrid18.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "rodin.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kj.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.biscuits.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "pl242v_sea02.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "purgedemo.example.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ak2.vaz.ac", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.168.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "imrtks.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "soorajb.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "shock1.iwishtechdemoswere.cool.edgesuite-staging.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "khunter.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.nmohammad-sfo.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jake.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "rdias-london.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "cztest2.sanbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dmbsdemo8.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "geekgonenomad.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "khide.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev-www.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "pravin-costco.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "devhack7.sanguinesoul.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dshafik.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dquintero.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "bendell.ca", + "policyNames": [ + "Bot" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "mk12345.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test111.randomnoise.us", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.kirstenscats.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jgarza-sea5-dev.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dh.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jackieliuawesome.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "faster.akamaidev.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static-hk.zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "terraform-example-1.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jgarza-sea5.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.krao-bangalore.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akadev2tree.interlude.org.uk.internal", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "saurabh-demo.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.config-as-code.web.astronaut.training", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "vangeler.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edgeworkers.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dynamic.zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.rdias-london.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edgeworld.web.astronaut.training", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "2.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "domwuttke.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "johnsmith-wt2.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.jgarza-sea.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h1cwnd10.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "3.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.brandonyap1-sydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.sangjinn-seoul.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "shock1.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "pravin-costco-dev.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.jcao_sydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "push-san.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "robertzimmardi.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.akamaihd.net.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tylake-addhosts.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api-acs.urbancrawlapp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tp8.utkarshgoel.in", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "1.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static-sg.zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dmopendemo.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "img.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "pl242v_att.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test97.randomnoise.us", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jackieliu.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "netstorage-test.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.24.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.barneys.me.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.171.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akadev.interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ak.vaz.ac", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.daveyshafik.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.domwuttke.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.prophostname1-origin1.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "qa.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "javier-madrid.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test67.randomnoise.us", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.jgarza-01.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "aarondotsteele.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "eddyl.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.5.gensess.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "testactivation2.example.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.dlovellsyd18.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.hermanw-sanfrancisco.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jose-ph.worldtour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "www.slackware.com", + "policyNames": [ + "Slackware Sites" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.msltest-lh.akamaihd.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static.sg.zalora.net.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api.zalora.sg.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dom.akamai.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.synedra.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jgarza3.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "javiergarza-20180911.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.princesspolymath.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "joncarva3.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "pkok.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.219.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.hwang-la2019.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dmbsdemo7.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.hsn-bellevue.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tp9.utkarshgoel.in", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "5.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.316.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "raitaarakawa.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tomonori.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "qa-www.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tai.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api.zalora.com.hk.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "purge.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "siraj01.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.ychao-singapore.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akaivadeveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "vpdemo.akamaiedge.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akamai7devhack.meepity.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.pcoirault-sydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "urbancrawlapp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "catfish.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "sravan1.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.api.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ak1.vaz.ac", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "amazon.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "api.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kohls.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.275.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "cloudmonitor.princesspolymath.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "stage.config-as-code.web.astronaut.training", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.yoav.ws", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.kirstenscats.com.edgesuite.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.barrington.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "devops.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edge2017-ezpc.www.wpl.akamaiuweb.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "zstatictw02-a.akamaihd.net.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "joncarva.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.akamaiapibootcamp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ankursi.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "bc.akamaiapibootcamp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "fareportal-mobile-xml.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "meetup2.example.com", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "www.biscuit.org.uk", + "policyNames": [ + "Slackware Sites" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "h1cwnd16.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akamaitools.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "awesome2.iwishtechdemoswere2.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static-sg.zalora.net.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jgarza-muc-int.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.328.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "failover.akadev.interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "smakki.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "js.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "cloudmonitor.akamaitools.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "erahman.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kirsten.im.edgesuite-staging.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.shouldipush.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.dsouzaa8g-sydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "sstest.akamaitools.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edge2017-ah01.www.wpl.akamaiuweb.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h1cwnd32.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.jgarza-20180928.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.urbancrawlapp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "gsiewhia.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akamaiapibootcamp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "shock1.iwishtechdemoswere.cool.edgesuite.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.money-mitch.world-tour.akamaidevelpoer.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "1.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "2tree.singledns.interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "soha.io.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "2ndakadev2tree.interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "test72.randomnoise.us", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "push.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tylake.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "wp-akamai.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "bootcamp.akamaiapibootcamp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "mwisborg.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "brain.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "diegoproperty.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.173.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h2cwnd24.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h2cwnd32.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "srjones.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "static-hg.zacdn.com.akamaiedgedemo.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.donfr-bellevue.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "4.bendell.ca", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "canipush.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "testactivation.example.com", + "policyNames": [], + "status": "not_covered" + }, + { + "configuration": { + "id": 3644, + "name": "WAF Security File", + "version": 12 + }, + "hasMatchTarget": true, + "hostname": "*.bendell.ca", + "policyNames": [ + "Bot" + ], + "status": "covered" + }, + { + "hasMatchTarget": false, + "hostname": "devops7.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.kirstenscats.com.edgesuite-staging.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "improxy.akam.ai", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "usage.akam.ai", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "edge2017-chad.www.wp1.akamaiuweb.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kirsten.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.akamaiapibootcamp.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "s2.daveyshafik.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akamai7devhack.akamaized.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.akamaidev.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.nverkland.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h2cwnd16.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "akadev2tree.interlude.org.uk", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.mkoerner.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "acedergr.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.akamaitools.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ksinghchapitestdevops.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "3.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "angautam.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "achoi.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev-www.akamaiedgedemo.com.local", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.hgsydney.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "docs.slackware.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "bchitrakar.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "psalvado.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "benlin.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "www.irresistibleapis.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "production.kirsten", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "shashi1.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.tarambale.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "*.shouldipush.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "ksinghchtest.sanbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "h2cwnd10.colinbendell.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "margaretkho.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "devhack4.iwishtechdemoswere.cool", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.ferdinand-amsterdamn", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "vlours.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "papin.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "dev.ogravier-paris.world-tour.akamaideveloper.net", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "schan.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "george-bc.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.184.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "n.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "jenkins.4.gensess.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "testing123.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "kweechuan1.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "anokulka.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "tomhartnett.sandbox.akamaideveloper.com", + "policyNames": [], + "status": "not_covered" + }, + { + "hasMatchTarget": false, + "hostname": "logstash.sztykman.com", + "policyNames": [], + "status": "not_covered" + } + ] + } diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/match_by_id.tf new file mode 100644 index 000000000..a4c34fd01 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverage/match_by_id.tf @@ -0,0 +1,8 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_hostname_coverage" "test" { + +} + diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/ApiHostnameCoverageMatchTargets.json b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/ApiHostnameCoverageMatchTargets.json new file mode 100644 index 000000000..9c25cac1e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/ApiHostnameCoverageMatchTargets.json @@ -0,0 +1,85 @@ +{ + "matchTargets": { + "apiTargets": [], + "websiteTargets": [ + { + "bypassNetworkLists": [ + { + "id": "1410_BYPASSWAFLIST", + "name": "gus - BypassWAFList" + } + ], + "configId": 2481, + "configVersion": 428, + "defaultFile": "NO_MATCH", + "effectiveSecurityControls": { + "applyApplicationLayerControls": true, + "applyBotmanControls": true, + "applyNetworkLayerControls": true, + "applyPageIntegrityControls": false, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": true + }, + "fileExtensions": [], + "filePaths": [ + "/content/tealeaf" + ], + "firewallPolicy": { + "evaluated": false, + "policyId": "GRD_4186", + "policyName": "Grainger USA", + "policySecurityControls": { + "applyApiConstraints": false, + "applyApplicationLayerControls": true, + "applyBotmanControls": true, + "applyNetworkLayerControls": true, + "applyPageIntegrityControls": false, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": true + } + }, + "hostnames": [ + "failover-m.lt.gcom.grainger.com", + "www.grainger.com", + "m.grainger.com", + "failover-m.lt2.gcom.grainger.com", + "keepstockselectiontool.grainger.com", + "failover-m.grainger.com", + "m.new.grainger.com", + "template-www.grainger.com", + "a.gc1.co", + "safety.grainger.com", + "static.grainger.net", + "failover-www.grainger.com", + "s.gc1.co", + "static.grainger.com", + "lt2.gcom.grainger.com", + "m.lt2.gcom.grainger.com", + "images.grainger.com", + "akamai-test.qa.graingercloud.com", + "failover-lt2.gcom.grainger.com", + "www.keepstocksecuredemo.com", + "waffailover.grainger.com", + "espanol.grainger.com" + ], + "isNegativeFileExtensionMatch": false, + "isNegativePathMatch": false, + "isTargetSecurityControlsEditable": false, + "logicalId": 1730010, + "sequence": 3, + "targetId": 2555705, + "targetSecurityControls": { + "applyApplicationLayerControls": true, + "applyNetworkLayerControls": true, + "applyPageIntegrityControls": false, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": true + }, + "type": "website" + } + ] + } +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/match_by_id.tf new file mode 100644 index 000000000..3318f34e7 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageMatchTargets/match_by_id.tf @@ -0,0 +1,9 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_hostname_coverage_match_targets" "test" { + config_id = 43253 + version = 7 + hostname = "rinaldi.sandbox.akamaideveloper.com" +} diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/ApiHostnameCoverageOverlapping.json b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/ApiHostnameCoverageOverlapping.json new file mode 100644 index 000000000..7a4f417ea --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/ApiHostnameCoverageOverlapping.json @@ -0,0 +1,9 @@ +[ + { + "type": "https://problems.luna.akamaiapis.net/appsec/error-types/INVALID-INPUT-ERROR", + "status": 400, + "title": "Invalid Input Error", + "detail": "Hostname should not be null or empty.", + "instance": "https://problems.luna.akamaiapis.net/appsec/error-instances/bed82d19-4bb8-48ea-a9e8-8f89979bf63e" + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/match_by_id.tf new file mode 100644 index 000000000..5bf4b13b7 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiHostnameCoverageOverlapping/match_by_id.tf @@ -0,0 +1,9 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_hostname_coverage_overlapping" "test" { + config_id = 43253 + version = 7 + hostname = "example.com" +} diff --git a/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/ApiRequestConstraints.json b/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/ApiRequestConstraints.json new file mode 100644 index 000000000..d68b73fc9 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/ApiRequestConstraints.json @@ -0,0 +1,3 @@ +{ + "action": "alert" +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/match_by_id.tf new file mode 100644 index 000000000..feb837d20 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSApiRequestConstraints/match_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +data "akamai_appsec_api_request_constraints" "test" { + config_id = 43253 + version = 7 + security_policy_id = "AAAA_81230" + api_id = 1 +} diff --git a/pkg/providers/appsec/testdata/TestDSAttackGroupActions/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSAttackGroupActions/match_by_id.tf index 072d21661..37019acd3 100644 --- a/pkg/providers/appsec/testdata/TestDSAttackGroupActions/match_by_id.tf +++ b/pkg/providers/appsec/testdata/TestDSAttackGroupActions/match_by_id.tf @@ -1,5 +1,6 @@ provider "akamai" { edgerc = "~/.edgerc" + //version = "1.0.1" } diff --git a/pkg/providers/appsec/testdata/TestDSAttackGroupConditionException/AttackGroupConditionException.json b/pkg/providers/appsec/testdata/TestDSAttackGroupConditionException/AttackGroupConditionException.json index d3c6f6c52..c137d6dae 100644 --- a/pkg/providers/appsec/testdata/TestDSAttackGroupConditionException/AttackGroupConditionException.json +++ b/pkg/providers/appsec/testdata/TestDSAttackGroupConditionException/AttackGroupConditionException.json @@ -1,4 +1,4 @@ -[ + { "ruleActions": [ { @@ -1283,4 +1283,3 @@ } ] } -] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/BypassNetworkLists.json b/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/BypassNetworkLists.json new file mode 100644 index 000000000..97f204f44 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/BypassNetworkLists.json @@ -0,0 +1,12 @@ +{ + "networkLists": [ + { + "name": "Test network list 1", + "id": "888518_ACDDCKERS" + }, + { + "name": "Test network list 2", + "id": "1304427_AAXXBBLIST" + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/match_by_id.tf new file mode 100644 index 000000000..2c63eb790 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSBypassNetworkLists/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +data "akamai_appsec_bypass_network_lists" "test" { +config_id = 43253 + version = 7 + +} + + + diff --git a/pkg/providers/appsec/testdata/TestDSContractsGroups/ContractsGroups.json b/pkg/providers/appsec/testdata/TestDSContractsGroups/ContractsGroups.json new file mode 100644 index 000000000..4d4f23ee8 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSContractsGroups/ContractsGroups.json @@ -0,0 +1,25 @@ + + { + "contract_groups": [ + { + "contractId": "C-1FRYVV3", + "displayName": "Akamai DevRel", + "groupId": 64867 + }, + { + "contractId": "C-1FRYVV3", + "displayName": "akava-test", + "groupId": 173935 + }, + { + "contractId": "C-1FRYVV3", + "displayName": "code-club-2020", + "groupId": 178167 + }, + { + "contractId": "C-1FRYVV3", + "displayName": "Josh Cheshire", + "groupId": 181212 + } + ] + } diff --git a/pkg/providers/appsec/testdata/TestDSContractsGroups/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSContractsGroups/match_by_id.tf new file mode 100644 index 000000000..314397d1d --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSContractsGroups/match_by_id.tf @@ -0,0 +1,7 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +data "akamai_appsec_contracts_groups" "test" { +} diff --git a/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDeny.json b/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDeny.json new file mode 100644 index 000000000..f356047de --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDeny.json @@ -0,0 +1,27 @@ +{ + "description": "Custom Deny Example 1", + "name": "Custom Deny Example 1", + "id": "deny_custom_54994", + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "body comes here2222." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDenyList.json b/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDenyList.json new file mode 100644 index 000000000..4758318f5 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSCustomDeny/CustomDenyList.json @@ -0,0 +1,59 @@ + + { + "customDenyList": [ + { + "description": "Custom Deny Example 1", + "name": "Custom Deny Example 1", + "id": "deny_custom_54994", + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "body comes here2222." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + }, + { + "description": "Custom Deny Example 2", + "name": "Custom Deny Example 2", + "id": 622919, + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "response body." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + } + ] + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSCustomDeny/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSCustomDeny/match_by_id.tf new file mode 100644 index 000000000..f7d44f2f4 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSCustomDeny/match_by_id.tf @@ -0,0 +1,10 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_custom_deny" "test" { + config_id = 43253 + version = 7 + custom_deny_id = "deny_custom_54994" +} + diff --git a/pkg/providers/appsec/testdata/TestDSEvalHostnames/EvalHostnames.json b/pkg/providers/appsec/testdata/TestDSEvalHostnames/EvalHostnames.json new file mode 100644 index 000000000..e0c0715d3 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSEvalHostnames/EvalHostnames.json @@ -0,0 +1,7 @@ +{ + "hostnames": [ + "*.example.net", + "example.com", + "m.example.com" + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSEvalHostnames/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSEvalHostnames/match_by_id.tf new file mode 100644 index 000000000..e53121f57 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSEvalHostnames/match_by_id.tf @@ -0,0 +1,9 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_eval_hostnames" "test" { + config_id = 43253 + version = 7 +} + diff --git a/pkg/providers/appsec/testdata/TestDSFailoverHostnames/FailoverHostnames.json b/pkg/providers/appsec/testdata/TestDSFailoverHostnames/FailoverHostnames.json new file mode 100644 index 000000000..fbcd333c7 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSFailoverHostnames/FailoverHostnames.json @@ -0,0 +1,5 @@ +[ + { + "hostnameList": [] + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSFailoverHostnames/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSFailoverHostnames/match_by_id.tf new file mode 100644 index 000000000..0f33faca1 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSFailoverHostnames/match_by_id.tf @@ -0,0 +1,9 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_failover_hostnames" "test" { + config_id = 43253 +} + + diff --git a/pkg/providers/appsec/testdata/TestDSReputationAnalysis/ReputationAnalysis.json b/pkg/providers/appsec/testdata/TestDSReputationAnalysis/ReputationAnalysis.json new file mode 100644 index 000000000..28e4534de --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSReputationAnalysis/ReputationAnalysis.json @@ -0,0 +1,5 @@ + + { + "forwardSharedIPToHTTPHeaderAndSIEM": false, + "forwardToHTTPHeader": false + } diff --git a/pkg/providers/appsec/testdata/TestDSReputationAnalysis/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSReputationAnalysis/match_by_id.tf new file mode 100644 index 000000000..4a10db8b7 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSReputationAnalysis/match_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + +data "akamai_appsec_reputation_profile_analysis" "test" { + config_id = 43253 + version = 7 + security_policy_id = "AAAA_81230" +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSSiemDefinitions/SiemDefinitions.json b/pkg/providers/appsec/testdata/TestDSSiemDefinitions/SiemDefinitions.json new file mode 100644 index 000000000..9b5730e70 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSSiemDefinitions/SiemDefinitions.json @@ -0,0 +1,8 @@ +{ + "siemDefinitions": [ + { + "id": 1, + "name": "SIEM Version 01" + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSSiemDefinitions/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSSiemDefinitions/match_by_id.tf new file mode 100644 index 000000000..4882982af --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSSiemDefinitions/match_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + +data "akamai_appsec_siem_definitions" "test" { + siem_definition_name = "SIEM Version 01" +} + + diff --git a/pkg/providers/appsec/testdata/TestDSSiemSettings/SiemSettings.json b/pkg/providers/appsec/testdata/TestDSSiemSettings/SiemSettings.json new file mode 100644 index 000000000..83fb7eb1f --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSSiemSettings/SiemSettings.json @@ -0,0 +1,9 @@ +[ + { + "type": "https://problems.luna.akamaiapis.net/appsec-configuration/error-types/UNAUTHORIZED", + "status": 403, + "title": "Unauthorized Access/Action", + "detail": "You do not have the necessary access to perform this operation.", + "instance": "https://problems.luna.akamaiapis.net/appsec-configuration/error-instances/eea381926983628b" + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSSiemSettings/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSSiemSettings/match_by_id.tf new file mode 100644 index 000000000..445ace6aa --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSSiemSettings/match_by_id.tf @@ -0,0 +1,10 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_appsec_siem_settings" "test" { + config_id = 43253 + version = 7 +} + + diff --git a/pkg/providers/appsec/testdata/TestDSVersionNotes/VersionNotes.json b/pkg/providers/appsec/testdata/TestDSVersionNotes/VersionNotes.json new file mode 100644 index 000000000..af0ee2871 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSVersionNotes/VersionNotes.json @@ -0,0 +1,3 @@ +{ + "notes": "This is a version note." +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestDSVersionNotes/match_by_id.tf b/pkg/providers/appsec/testdata/TestDSVersionNotes/match_by_id.tf new file mode 100644 index 000000000..f6f70beb4 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestDSVersionNotes/match_by_id.tf @@ -0,0 +1,12 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + +data "akamai_appsec_version_notes" "test" { + config_id = 43253 + version = 7 +} + + diff --git a/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json b/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json new file mode 100644 index 000000000..574804661 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/AdvancedSettingsLogging.json @@ -0,0 +1,13 @@ + + { + "allowSampling": true, + "cookies": { + "type": "all" + }, + "customHeaders": { + "type": "all" + }, + "standardHeaders": { + "type": "all" + } + } diff --git a/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/match_by_id.tf b/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/match_by_id.tf new file mode 100644 index 000000000..b9f6bc85a --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResAdvancedSettingsLogging/match_by_id.tf @@ -0,0 +1,29 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_advanced_settings_logging" "test" { + config_id = 43253 + version = 7 + logging = <<-EOF +{ + "allowSampling": true, + "cookies": { + "type": "all" + }, + "customHeaders": { + "type": "exclude", + "values": [ + "csdasdad" + ] + }, + "standardHeaders": { + "type": "only", + "values": [ + "Accept" + ] + } +} +EOF +} diff --git a/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json b/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json new file mode 100644 index 000000000..28fa3dc0e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/AdvancedSettingsPrefetch.json @@ -0,0 +1,15 @@ + + { + "allExtensions": false, + "enableAppLayer": true, + "enableRateControls": false, + "extensions": [ + "cgi", + "jsp", + "aspx", + "EMPTY_STRING", + "php", + "py", + "asp" + ] + } diff --git a/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/match_by_id.tf b/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/match_by_id.tf new file mode 100644 index 000000000..3738d5176 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResAdvancedSettingsPrefetch/match_by_id.tf @@ -0,0 +1,23 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_advanced_settings_prefetch" "test" { + config_id = 43253 + version = 7 + enable_app_layer = false + all_extensions = true + enable_rate_controls = false + extensions = [ + "cgi", + "jsp", + "aspx", + "EMPTY_STRING", + "php", + "py", + "asp" + ] +} + + + diff --git a/pkg/providers/appsec/testdata/TestResApiRequestConstraints/ApiRequestConstraints.json b/pkg/providers/appsec/testdata/TestResApiRequestConstraints/ApiRequestConstraints.json new file mode 100644 index 000000000..be871e5cc --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResApiRequestConstraints/ApiRequestConstraints.json @@ -0,0 +1,8 @@ +{ + "apiEndpoints": [ + { + "action": "alert", + "id": 1 + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResApiRequestConstraints/match_by_id.tf b/pkg/providers/appsec/testdata/TestResApiRequestConstraints/match_by_id.tf new file mode 100644 index 000000000..482c10fdb --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResApiRequestConstraints/match_by_id.tf @@ -0,0 +1,14 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_api_request_constraints" "test" { +config_id = 43253 + version = 7 + security_policy_id = "AAAA_81230" + api_endpoint_id = 1 + action = "alert" +} + + diff --git a/pkg/providers/appsec/testdata/TestResBypassNetworkLists/BypassNetworkLists.json b/pkg/providers/appsec/testdata/TestResBypassNetworkLists/BypassNetworkLists.json new file mode 100644 index 000000000..97f204f44 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResBypassNetworkLists/BypassNetworkLists.json @@ -0,0 +1,12 @@ +{ + "networkLists": [ + { + "name": "Test network list 1", + "id": "888518_ACDDCKERS" + }, + { + "name": "Test network list 2", + "id": "1304427_AAXXBBLIST" + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResBypassNetworkLists/match_by_id.tf b/pkg/providers/appsec/testdata/TestResBypassNetworkLists/match_by_id.tf new file mode 100644 index 000000000..8d4de4fd0 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResBypassNetworkLists/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_bypass_network_lists" "test" { + config_id = 43253 + version = 7 + bypass_network_list = ["888518_ACDDCKERS","1304427_AAXXBBLIST"] + +} + + diff --git a/pkg/providers/appsec/testdata/TestResConfiguration/Configuration.json b/pkg/providers/appsec/testdata/TestResConfiguration/Configuration.json new file mode 100644 index 000000000..645741f1e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfiguration/Configuration.json @@ -0,0 +1,54 @@ + + { + "configurations": [ + { + "description": "Akamai Tools", + "fileType": "RBAC", + "id": 43253, + "latestVersion": 23, + "name": "Akamai Tools", + "targetProduct": "KSD" + }, + { + "description": "Akamai Tools", + "fileType": "RBAC", + "id": 432531, + "latestVersion": 23, + "name": "Akamai Tools New", + "targetProduct": "KSD" + }, + { + "fileType": "RBAC", + "id": 39085, + "latestVersion": 35, + "name": "Example for EDGE", + "targetProduct": "KSD" + }, + { + "description": "Restrictions for WT events", + "fileType": "RBAC", + "id": 24728, + "latestVersion": 1, + "name": "WorldTour", + "targetProduct": "KSD" + }, + { + "fileType": "WAF", + "id": 3644, + "latestVersion": 13, + "name": "WAF Security File", + "productionHostnames": [ + "*.bendell.ca", + "bendell.ca", + "www.biscuit.org.uk", + "*.colinbendell.com", + "www.colinbendell.com", + "www.slackware.com", + "arm.slackware.com" + ], + "productionVersion": 12, + "stagingVersion": 12, + "targetProduct": "KSD" + } + ] + } diff --git a/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationCreate.json b/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationCreate.json new file mode 100644 index 000000000..2eb98aae2 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationCreate.json @@ -0,0 +1,6 @@ +{ + "configId": 432531, + "version": 1, + "description": "description1", + "name": "Akamai Tools New" +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationUpdate.json b/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationUpdate.json new file mode 100644 index 000000000..33c339d6c --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfiguration/ConfigurationUpdate.json @@ -0,0 +1,5 @@ + + { + "description": "Akamai Tools", + "name": "Akamai Tools New" + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResConfiguration/match_by_id.tf b/pkg/providers/appsec/testdata/TestResConfiguration/match_by_id.tf new file mode 100644 index 000000000..5dacf8de3 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfiguration/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_configuration" "test" { + name = "Akamai Tools New" + description = "TF Tools" + contract_id= "C-1FRYVV3" + group_id = 64867 + host_names = ["rinaldi.sandbox.akamaideveloper.com", + "sujala.sandbox.akamaideveloper.com"] +} + diff --git a/pkg/providers/appsec/testdata/TestResConfiguration/update_by_id.tf b/pkg/providers/appsec/testdata/TestResConfiguration/update_by_id.tf new file mode 100644 index 000000000..c6c163399 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfiguration/update_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_configuration" "test" { + name = "Akamai Tools New" + description = "TF Tools 1" + contract_id= "C-1FRYVV3" + group_id = 64867 + host_names = ["rinaldi.sandbox.akamaideveloper.com", + "sujala.sandbox.akamaideveloper.com"] +} + diff --git a/pkg/providers/appsec/testdata/TestResConfigurationClone/match_by_id.tf b/pkg/providers/appsec/testdata/TestResConfigurationClone/match_by_id.tf index 27cf3b487..ed32aae27 100644 --- a/pkg/providers/appsec/testdata/TestResConfigurationClone/match_by_id.tf +++ b/pkg/providers/appsec/testdata/TestResConfigurationClone/match_by_id.tf @@ -3,9 +3,13 @@ provider "akamai" { } -resource "akamai_appsec_configuration_version_clone" "test" { - config_id = 43253 - create_from_version = 7 - rule_update = false +resource "akamai_appsec_configuration_clone" "test" { + create_from_config_id = 43253 + create_from_version = 7 + name = "Test Configuratin" + description = "New configuration test" + contract_id= "C-1FRYVV3" + group_id = "64867" + host_names = ["rinaldi.sandbox.akamaideveloper.com","sujala.sandbox.akamaideveloper.com"] } diff --git a/pkg/providers/appsec/testdata/TestResConfigurationClone/test.json b/pkg/providers/appsec/testdata/TestResConfigurationClone/test.json new file mode 100644 index 000000000..2f050e959 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationClone/test.json @@ -0,0 +1,14 @@ +{ +   "name": "New Clone config", +   "description": "description1", +   "contractId": "C-AVLN15", +   "groupId": 42085, +   "hostnames": [ +     "new.acklandsgrainger.com", +     "www.acklandsgrainger.com" +   ], +  "createFrom": { +     "configId": 56879, +     "version": 3 +   } +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResConfigurationRename/Configuration.json b/pkg/providers/appsec/testdata/TestResConfigurationRename/Configuration.json new file mode 100644 index 000000000..645741f1e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationRename/Configuration.json @@ -0,0 +1,54 @@ + + { + "configurations": [ + { + "description": "Akamai Tools", + "fileType": "RBAC", + "id": 43253, + "latestVersion": 23, + "name": "Akamai Tools", + "targetProduct": "KSD" + }, + { + "description": "Akamai Tools", + "fileType": "RBAC", + "id": 432531, + "latestVersion": 23, + "name": "Akamai Tools New", + "targetProduct": "KSD" + }, + { + "fileType": "RBAC", + "id": 39085, + "latestVersion": 35, + "name": "Example for EDGE", + "targetProduct": "KSD" + }, + { + "description": "Restrictions for WT events", + "fileType": "RBAC", + "id": 24728, + "latestVersion": 1, + "name": "WorldTour", + "targetProduct": "KSD" + }, + { + "fileType": "WAF", + "id": 3644, + "latestVersion": 13, + "name": "WAF Security File", + "productionHostnames": [ + "*.bendell.ca", + "bendell.ca", + "www.biscuit.org.uk", + "*.colinbendell.com", + "www.colinbendell.com", + "www.slackware.com", + "arm.slackware.com" + ], + "productionVersion": 12, + "stagingVersion": 12, + "targetProduct": "KSD" + } + ] + } diff --git a/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationCreate.json b/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationCreate.json new file mode 100644 index 000000000..2eb98aae2 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationCreate.json @@ -0,0 +1,6 @@ +{ + "configId": 432531, + "version": 1, + "description": "description1", + "name": "Akamai Tools New" +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationUpdate.json b/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationUpdate.json new file mode 100644 index 000000000..33c339d6c --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationRename/ConfigurationUpdate.json @@ -0,0 +1,5 @@ + + { + "description": "Akamai Tools", + "name": "Akamai Tools New" + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResConfigurationRename/match_by_id.tf b/pkg/providers/appsec/testdata/TestResConfigurationRename/match_by_id.tf new file mode 100644 index 000000000..55248b4ec --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationRename/match_by_id.tf @@ -0,0 +1,10 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_configuration_rename" "test" { + name = "Akamai Tools New" + description = "TF Tools" + config_id = 432531 +} + diff --git a/pkg/providers/appsec/testdata/TestResConfigurationRename/update_by_id.tf b/pkg/providers/appsec/testdata/TestResConfigurationRename/update_by_id.tf new file mode 100644 index 000000000..55248b4ec --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationRename/update_by_id.tf @@ -0,0 +1,10 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_configuration_rename" "test" { + name = "Akamai Tools New" + description = "TF Tools" + config_id = 432531 +} + diff --git a/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json b/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json new file mode 100644 index 000000000..e9d01666d --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/ConfigurationVersionClone.json @@ -0,0 +1,15 @@ + + { + "basedOn": 7, + "configId": 43253, + "configName": "Akamai Tools", + "createDate": "2020-10-06T18:00:20Z", + "createdBy": "akava-terraform", + "production": { + "status": "Inactive" + }, + "staging": { + "status": "Inactive" + }, + "version": 15 + } diff --git a/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/match_by_id.tf b/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/match_by_id.tf new file mode 100644 index 000000000..27cf3b487 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResConfigurationVersionClone/match_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_configuration_version_clone" "test" { + config_id = 43253 + create_from_version = 7 + rule_update = false + } + diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDeny.json b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDeny.json new file mode 100644 index 000000000..df5a86908 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDeny.json @@ -0,0 +1,28 @@ + + { + "description": "Custom Deny Example 1", + "name": "Custom Deny Example 1", + "id": "deny_custom_622918", + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "body comes here2222." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyCreate.json b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyCreate.json new file mode 100644 index 000000000..7a8a58810 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyCreate.json @@ -0,0 +1,24 @@ +{ + "name": "new_custom_deny", + "description": "testing", + "isPageUrl" : false, + "id": "deny_custom_622918", + "parameters": [ + { + "name": "response_status_code", + "value": "403" + }, + { + "name": "prevent_browser_cache", + "value": "true" + }, + { + "name": "response_content_type", + "value": "application/json" + }, + { + "name": "response_body_content", + "value": "new testing" + } + ] +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyList.json b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyList.json new file mode 100644 index 000000000..e1e566f58 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyList.json @@ -0,0 +1,59 @@ + + { + "customDenyList": [ + { + "description": "Custom Deny Example 1", + "name": "Custom Deny Example 1", + "id": "deny_custom_622918", + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "body comes here2222." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + }, + { + "description": "Custom Deny Example 2", + "name": "Custom Deny Example 2", + "id": 622919, + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "true" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "response body." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + } + ] + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyUpdate.json b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyUpdate.json new file mode 100644 index 000000000..ca803e3f7 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/CustomDenyUpdate.json @@ -0,0 +1,28 @@ + + { + "description": "Custom Deny Example 1", + "name": "Custom Deny Example 1", + "id": "deny_custom_622918", + "parameters": [ + { + "displayName": "Prevent browser caching", + "name": "prevent_browser_cache", + "value": "false" + }, + { + "displayName": "Response body content", + "name": "response_body_content", + "value": "body comes here2222." + }, + { + "displayName": "Response content type", + "name": "response_content_type", + "value": "application/json" + }, + { + "displayName": "Response status code", + "name": "response_status_code", + "value": "403" + } + ] + } \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/match_by_id.tf b/pkg/providers/appsec/testdata/TestResCustomDeny/match_by_id.tf new file mode 100644 index 000000000..c510c8160 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/match_by_id.tf @@ -0,0 +1,36 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_custom_deny" "test" { + config_id = 43253 + version = 7 + custom_deny = <<-EOF +{ + "name": "new_custom_deny", + "description": "testing", + "isPageUrl" : false, + "parameters": [ + { + "name": "response_status_code", + "value": "403" + }, + { + "name": "prevent_browser_cache", + "value": "true" + }, + { + "name": "response_content_type", + "value": "application/json" + }, + { + "name": "response_body_content", + "value": "new testing" + } + ] +} +EOF +} + + + diff --git a/pkg/providers/appsec/testdata/TestResCustomDeny/update_by_id.tf b/pkg/providers/appsec/testdata/TestResCustomDeny/update_by_id.tf new file mode 100644 index 000000000..c11e4b65b --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResCustomDeny/update_by_id.tf @@ -0,0 +1,36 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_custom_deny" "test" { + config_id = 43253 + version = 7 + custom_deny = <<-EOF +{ + "name": "new_custom_deny", + "description": "testing", + "isPageUrl" : false, + "parameters": [ + { + "name": "response_status_code", + "value": "403" + }, + { + "name": "prevent_browser_cache", + "value": "false" + }, + { + "name": "response_content_type", + "value": "application/json" + }, + { + "name": "response_body_content", + "value": "new testing" + } + ] +} +EOF +} + + + diff --git a/pkg/providers/appsec/testdata/TestResEvalHost/EvalHost.json b/pkg/providers/appsec/testdata/TestResEvalHost/EvalHost.json new file mode 100644 index 000000000..60f9d6576 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResEvalHost/EvalHost.json @@ -0,0 +1,9 @@ +[ + { + "type": "https://problems.luna.akamaiapis.net/appsec/error-types/INVALID-INPUT-ERROR", + "status": 400, + "title": "Invalid Input Error", + "detail": "Config(43253) is not of type WAP (Web Application Protector).", + "instance": "https://problems.luna.akamaiapis.net/appsec/error-instances/b6a06093-2ea0-456a-8056-7d0edeb3c311" + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResEvalHost/match_by_id.tf b/pkg/providers/appsec/testdata/TestResEvalHost/match_by_id.tf new file mode 100644 index 000000000..8378af3ee --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResEvalHost/match_by_id.tf @@ -0,0 +1,12 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_eval_hostnames" "test" { + config_id = 43253 + version = 7 + hostnames = ["example.com"] +} + + + diff --git a/pkg/providers/appsec/testdata/TestResEvalProtectHost/EvalProtectHost.json b/pkg/providers/appsec/testdata/TestResEvalProtectHost/EvalProtectHost.json new file mode 100644 index 000000000..01f62e40d --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResEvalProtectHost/EvalProtectHost.json @@ -0,0 +1,5 @@ +[ + { + "action": "none" + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResEvalProtectHost/match_by_id.tf b/pkg/providers/appsec/testdata/TestResEvalProtectHost/match_by_id.tf new file mode 100644 index 000000000..819cafd5d --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResEvalProtectHost/match_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_eval_protect_host" "test" { + config_id = 43253 + version = 7 + hostnames = ["example.com"] +} + + diff --git a/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysis.json b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysis.json new file mode 100644 index 000000000..13528a085 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysis.json @@ -0,0 +1,5 @@ + + { + "forwardSharedIPToHTTPHeaderAndSIEM": true, + "forwardToHTTPHeader": true + } diff --git a/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisDelete.json b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisDelete.json new file mode 100644 index 000000000..28e4534de --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisDelete.json @@ -0,0 +1,5 @@ + + { + "forwardSharedIPToHTTPHeaderAndSIEM": false, + "forwardToHTTPHeader": false + } diff --git a/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisUpdated.json b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisUpdated.json new file mode 100644 index 000000000..13528a085 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResReputationAnalysis/ReputationAnalysisUpdated.json @@ -0,0 +1,5 @@ + + { + "forwardSharedIPToHTTPHeaderAndSIEM": true, + "forwardToHTTPHeader": true + } diff --git a/pkg/providers/appsec/testdata/TestResReputationAnalysis/match_by_id.tf b/pkg/providers/appsec/testdata/TestResReputationAnalysis/match_by_id.tf new file mode 100644 index 000000000..b105a82ae --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResReputationAnalysis/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_reputation_profile_analysis" "test" { + config_id = 43253 + version = 12 + security_policy_id = "AAAA_81230" + forward_to_http_header = true + forward_shared_ip_to_http_header_siem = true +} + diff --git a/pkg/providers/appsec/testdata/TestResReputationAnalysis/update_by_id.tf b/pkg/providers/appsec/testdata/TestResReputationAnalysis/update_by_id.tf new file mode 100644 index 000000000..b105a82ae --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResReputationAnalysis/update_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_reputation_profile_analysis" "test" { + config_id = 43253 + version = 12 + security_policy_id = "AAAA_81230" + forward_to_http_header = true + forward_shared_ip_to_http_header_siem = true +} + diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicies.json b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicies.json new file mode 100644 index 000000000..01536813e --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicies.json @@ -0,0 +1,20 @@ +[ + { + "configId": 43253, + "policies": [ + { + "policyId": "AAAA_81230", + "policyName": "akamaitools" + }, + { + "policyId": "PLE_114049", + "policyName": "PLE Cloned Test for Launchpad 21" + }, + { + "policyId": "PLD_113982", + "policyName": "PLD Cloned Test for Launchpad 21" + } + ], + "version": 15 + } +] \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicy.json b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicy.json new file mode 100644 index 000000000..9253cdbe0 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicy.json @@ -0,0 +1,15 @@ +{ + "configId": 43253, + "version": 7, + "policyId": "PLE_114049", + "policyName": "PLE Cloned Test for Launchpad 151", + "policySecurityControls": { + "applyApiConstraints": true, + "applyApplicationLayerControls": true, + "applyBotmanControls": true, + "applyNetworkLayerControls": true, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": false + } +} diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyCreate.json b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyCreate.json new file mode 100644 index 000000000..ce4b0218b --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyCreate.json @@ -0,0 +1,16 @@ +{ + "configId": 43253, + "version": 7, + "policyId": "PLE_114049", + "policyName": "PLE Cloned Test for Launchpad 15", + "policyPrefix": "PL", + "policySecurityControls": { + "applyApiConstraints": true, + "applyApplicationLayerControls": true, + "applyBotmanControls": true, + "applyNetworkLayerControls": true, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": false + } +} diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyUpdate.json b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyUpdate.json new file mode 100644 index 000000000..d93595947 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/SecurityPolicyUpdate.json @@ -0,0 +1,16 @@ +{ + "configId": 43253, + "version": 7, + "policyId": "PLE_114049", + "policyName": "Cloned Test for Launchpad 15", + "policyPrefix": "PL", + "policySecurityControls": { + "applyApiConstraints": true, + "applyApplicationLayerControls": true, + "applyBotmanControls": true, + "applyNetworkLayerControls": true, + "applyRateControls": true, + "applyReputationControls": true, + "applySlowPostControls": false + } +} diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/match_by_id.tf b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/match_by_id.tf new file mode 100644 index 000000000..ed3c1cadb --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/match_by_id.tf @@ -0,0 +1,12 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + +resource "akamai_appsec_security_policy_rename" "test" { + config_id = 43253 + version = 7 + security_policy_name = "Cloned Test for Launchpad 15" + security_policy_id = "PLE_114049" + } + diff --git a/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/update_by_id.tf b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/update_by_id.tf new file mode 100644 index 000000000..940fb13a8 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSecurityPolicyRename/update_by_id.tf @@ -0,0 +1,11 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +resource "akamai_appsec_security_policy_rename" "test" { + config_id = 43253 + version = 7 + security_policy_name = "Cloned Test for Launchpad 15" + security_policy_id = "PLE_114049" + } + diff --git a/pkg/providers/appsec/testdata/TestResSiemSettings/SiemSettings.json b/pkg/providers/appsec/testdata/TestResSiemSettings/SiemSettings.json new file mode 100644 index 000000000..415bc545c --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSiemSettings/SiemSettings.json @@ -0,0 +1,6 @@ +{ + "enableForAllPolicies": true, + "enableSiem": true, + "enabledBotmanSiemEvents": false, + "siemDefinitionId": 1 +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResSiemSettings/match_by_id.tf b/pkg/providers/appsec/testdata/TestResSiemSettings/match_by_id.tf new file mode 100644 index 000000000..f6807eab6 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResSiemSettings/match_by_id.tf @@ -0,0 +1,18 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + + +resource "akamai_appsec_siem_settings" "test" { + config_id = 43253 + version = 7 + enable_siem = true + enable_for_all_policies = false + enable_botman_siem = true + siem_id = 1 //data.akamai_appsec_siem_definitions.siem_definition.id + security_policy_ids = [12345]//data.akamai_appsec_security_policy.security_policies.policy_ids +} + + diff --git a/pkg/providers/appsec/testdata/TestResVersionNotes/VersionNotes.json b/pkg/providers/appsec/testdata/TestResVersionNotes/VersionNotes.json new file mode 100644 index 000000000..af0ee2871 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResVersionNotes/VersionNotes.json @@ -0,0 +1,3 @@ +{ + "notes": "This is a version note." +} \ No newline at end of file diff --git a/pkg/providers/appsec/testdata/TestResVersionNotes/match_by_id.tf b/pkg/providers/appsec/testdata/TestResVersionNotes/match_by_id.tf new file mode 100644 index 000000000..dc7a43654 --- /dev/null +++ b/pkg/providers/appsec/testdata/TestResVersionNotes/match_by_id.tf @@ -0,0 +1,13 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + + + +resource "akamai_appsec_version_notes" "test" { + config_id = 43253 + version = 7 + version_notes = "Test Notes" +} + + diff --git a/pkg/providers/dns/resource_akamai_dns_record.go b/pkg/providers/dns/resource_akamai_dns_record.go index 38fa73283..6a9cdd366 100644 --- a/pkg/providers/dns/resource_akamai_dns_record.go +++ b/pkg/providers/dns/resource_akamai_dns_record.go @@ -81,6 +81,8 @@ func resourceDNSv2Record() *schema.Resource { RRTypeCaa, RRTypeCert, RRTypeTlsa, + RRTypeSvcb, + RRTypeHttps, }, false), }, "ttl": { @@ -310,6 +312,18 @@ func resourceDNSv2Record() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "svc_priority": { + Type: schema.TypeInt, + Optional: true, + }, + "svc_params": { + Type: schema.TypeString, + Optional: true, + }, + "target_name": { + Type: schema.TypeString, + Optional: true, + }, }, } } @@ -519,7 +533,7 @@ func diffQuotedDNSRecord(oldTargetList []string, newTargetList []string, old str return false } - if recordType == RRTypeAfsdb || recordType == RRTypeCname || recordType == RRTypePtr || recordType == RRTypeSrv { + if recordType == RRTypeAfsdb || recordType == RRTypeCname || recordType == RRTypePtr || recordType == RRTypeSrv || recordType == RRTypeNs { baseVal = strings.TrimRight(baseVal, ".") for _, compval := range compList { compval = strings.TrimRight(compval, ".") @@ -571,6 +585,8 @@ var recordCreateLock = map[string]*sync.Mutex{ "NSEC3": {}, "NSEC3PARAM": {}, "RRSIG": {}, + "SVCB": {}, + "HTTPS": {}, } // Retrieves record lock per record type @@ -1933,6 +1949,22 @@ func newRecordCreate(ctx context.Context, meta akamai.OperationMeta, d *schema.R records := []string{strconv.Itoa(usage) + " " + strconv.Itoa(selector) + " " + strconv.Itoa(matchtype) + " " + certificate} recordCreate = dns.RecordBody{Name: host, RecordType: recordType, TTL: ttl, Target: records} + case RRTypeSvcb, RRTypeHttps: + pri, err := tools.GetIntValue("svc_priority", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return dns.RecordBody{}, err + } + tname, err := tools.GetStringValue("target_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return dns.RecordBody{}, err + } + params, err := tools.GetStringValue("svc_params", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return dns.RecordBody{}, err + } + records := []string{strconv.Itoa(pri) + " " + tname + " " + params} + recordCreate = dns.RecordBody{Name: host, RecordType: recordType, TTL: ttl, Target: records} + default: return dns.RecordBody{}, fmt.Errorf("unable to create a Record Body for %s : %s", host, recordType) } @@ -2045,6 +2077,10 @@ func validateRecord(d *schema.ResourceData) error { return checkCertRecord(d) case RRTypeTlsa: return checkTlsaRecord(d) + case RRTypeSvcb: + return checkSvcbRecord(d) + case RRTypeHttps: + return checkHttpsRecord(d) default: return fmt.Errorf("invalid recordtype %v", recordType) } @@ -2713,6 +2749,55 @@ func checkTlsaRecord(d *schema.ResourceData) error { } +func checkSvcbRecord(d *schema.ResourceData) error { + + return checkServiceRecord(d, "SVCB") +} + +func checkHttpsRecord(d *schema.ResourceData) error { + + return checkServiceRecord(d, "HTTPS") +} + +func checkServiceRecord(d *schema.ResourceData, rtype string) error { + + pri, err := tools.GetIntValue("svc_priority", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return err + } + tname, err := tools.GetStringValue("target_name", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return err + } + params, err := tools.GetStringValue("svc_params", d) + if err != nil && !errors.Is(err, tools.ErrNotFound) { + return err + } + + if err := checkBasicRecordTypes(d); err != nil { + return err + } + + if pri < 0 || pri > 65535 { + return fmt.Errorf("configuration argument svc_priority must be positive int for %s", rtype) + } + + if tname == "" { + return fmt.Errorf("configuration argument target_name must be set for %s", rtype) + } + + if params == "" && pri > 0 { + return fmt.Errorf("configuration argument svc_params must be set for %s", rtype) + } + + if pri == 0 && params != "" { + return fmt.Errorf("configuration argument svc_params cannot be set for %s if svc_priority is zero", rtype) + } + + return nil + +} + // Resource record types supported by the Akamai Edge DNS API const ( RRTypeA = "A" @@ -2741,4 +2826,6 @@ const ( RRTypeNsec3Param = "NSEC3PARAM" RRTypeRrsig = "RRSIG" RRTypeCert = "CERT" + RRTypeHttps = "HTTPS" + RRTypeSvcb = "SVCB" ) diff --git a/pkg/providers/dns/resource_akamai_dns_zone.go b/pkg/providers/dns/resource_akamai_dns_zone.go index 8fd0afdd6..ab25d3248 100644 --- a/pkg/providers/dns/resource_akamai_dns_zone.go +++ b/pkg/providers/dns/resource_akamai_dns_zone.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "os" "strings" "time" @@ -282,6 +283,26 @@ func resourceDNSv2ZoneRead(ctx context.Context, d *schema.ResourceData, m interf if strings.ToUpper(zone.Type) != strings.ToUpper(zoneType) { return diag.Errorf("zone type has changed from %s to %s", zoneType, zone.Type) } + if strings.ToUpper(zone.Type) == "PRIMARY" { + // TFP-196 - check if SOA and NS exist. If not, create + err = checkZoneSOAandNSRecords(ctx, meta, zone, logger) + if err != nil { + return append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Zone is in an indeterminate state", + Detail: err.Error(), + }) + } + // Need updated state + zone, err = inst.Client(meta).GetZone(ctx, hostname) + if err != nil { + return append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Zone read failure", + Detail: err.Error(), + }) + } + } if err := populateDNSv2ZoneState(d, zone); err != nil { return diag.FromErr(err) } @@ -392,6 +413,19 @@ func resourceDNSv2ZoneImport(d *schema.ResourceData, m interface{}) ([]*schema.R return nil, err } + if strings.ToUpper(zone.Type) == "PRIMARY" { + // TFP-196 - check if SOA and NS exist. If not, create + err = checkZoneSOAandNSRecords(ctx, meta, zone, logger) + if err != nil { + return nil, err + } + // Need updated state + zone, err = inst.Client(meta).GetZone(ctx, hostname) + if err != nil { + return nil, err + } + } + if err := d.Set("zone", zone.Zone); err != nil { return nil, fmt.Errorf("%w: %s", tools.ErrValueSet, err.Error()) } @@ -409,18 +443,22 @@ func resourceDNSv2ZoneImport(d *schema.ResourceData, m interface{}) ([]*schema.R } func resourceDNSv2ZoneDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - hostname, err := tools.GetStringValue("zone", d) if err != nil { return diag.FromErr(err) } meta := akamai.Meta(m) logger := meta.Log("AkamaiDNS", "resourceDNSZoneDelete") - logger.WithField("zone", hostname).Info("Zone Import") + logger.WithField("zone", hostname).Info("Zone Delete") + // Ignore for Unit test Lifecycle + if _, ok := os.LookupEnv("DNS_ZONE_SKIP_DELETE"); ok { + logger.Info("DNS Zone delete: intentially skipping") + return nil + } logger.Warn("DNS Zone deletion not allowed") // No ZONE delete operation permitted. - return schema.NoopContext(ctx, d, meta) + return diag.Errorf("DNS zone deletion is not supported via this sub provider") } // validateZoneType is a SchemaValidateFunc to validate the Zone type. @@ -600,3 +638,55 @@ func checkDNSv2Zone(d tools.ResourceDataFetcher) error { return nil } + +// Util func to create SOA and NS records +func checkZoneSOAandNSRecords(ctx context.Context, meta akamai.OperationMeta, zone *dns.ZoneResponse, logger log.Interface) error { + logger.Debugf("Checking SOA and NS records exist for zone %s", zone.Zone) + var resp *dns.RecordSetResponse + var err error + if zone.ActivationState != "NEW" { + // See if SOA and NS recs exist already. Both or none. + resp, err = inst.Client(meta).GetRecordsets(ctx, zone.Zone, dns.RecordsetQueryArgs{Types: "SOA,NS"}) + if err != nil { + return err + } + } + if resp != nil && len(resp.Recordsets) >= 2 { + return nil + } + + logger.Warnf("SOA and NS records don't exist. Creating ...") + nameservers, err := inst.Client(meta).GetNameServerRecordList(ctx, zone.ContractID) + if err != nil { + return err + } + if len(nameservers) < 1 { + return fmt.Errorf("No authoritative nameservers exist for zone %s contract ID", zone.Zone) + } + rs := &dns.Recordsets{Recordsets: make([]dns.Recordset, 0)} + rs.Recordsets = append(rs.Recordsets, createSOARecord(zone.Zone, nameservers, logger)) + rs.Recordsets = append(rs.Recordsets, createNSRecord(zone.Zone, nameservers, logger)) + + // create recordsets + err = inst.Client(meta).CreateRecordsets(ctx, rs, zone.Zone, true) + + return err +} + +func createSOARecord(zone string, nameservers []string, logger log.Interface) dns.Recordset { + rec := dns.Recordset{Name: zone, Type: "SOA"} + rec.TTL = 86400 + pemail := fmt.Sprintf("hostmaster.%s.", zone) + soaData := fmt.Sprintf("%s %s 1 14400 7200 604800 1200", nameservers[0], pemail) + rec.Rdata = []string{soaData} + + return rec +} + +func createNSRecord(zone string, nameservers []string, logger log.Interface) dns.Recordset { + rec := dns.Recordset{Name: zone, Type: "NS"} + rec.TTL = 86400 + rec.Rdata = nameservers + + return rec +} diff --git a/pkg/providers/dns/resource_akamai_dns_zone_test.go b/pkg/providers/dns/resource_akamai_dns_zone_test.go index 8f6388c2b..fdb6fdf18 100644 --- a/pkg/providers/dns/resource_akamai_dns_zone_test.go +++ b/pkg/providers/dns/resource_akamai_dns_zone_test.go @@ -1,22 +1,24 @@ package dns import ( - "net/http" - "testing" - dns "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/configdns" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/stretchr/testify/mock" + "net/http" + "os" + "testing" ) func TestResDnsZone(t *testing.T) { zone := &dns.ZoneResponse{ - ContractID: "ctr2", - Zone: "primaryexampleterraform.io", - Type: "primary", - Comment: "This is a test primary zone", - SignAndServe: false, + ContractID: "ctr2", + Zone: "primaryexampleterraform.io", + Type: "primary", + Comment: "This is a test primary zone", + SignAndServe: false, + ActivationState: "PENDING", } + recordsetsResp := &dns.RecordSetResponse{Recordsets: make([]dns.Recordset, 2, 2)} // This test peforms a full life-cycle (CRUD) test t.Run("lifecycle test", func(t *testing.T) { @@ -56,8 +58,17 @@ func TestResDnsZone(t *testing.T) { mock.AnythingOfType("*dns.ZoneCreate"), ).Return(nil) + client.On("GetRecordsets", + mock.Anything, // ctx is irrelevant for this test + zone.Zone, + mock.AnythingOfType("[]dns.RecordsetQueryArgs"), + ).Return(recordsetsResp, nil) + dataSourceName := "akamai_dns_zone.primary_test_zone" + // work around to skip Delete which fails intentionally + os.Setenv("DNS_ZONE_SKIP_DELETE", "") + defer os.Unsetenv("DNS_ZONE_SKIP_DELETE") useClient(client, func() { resource.UnitTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pkg/providers/gtm/resource_akamai_gtm_datacenter.go b/pkg/providers/gtm/resource_akamai_gtm_datacenter.go index b7d10a0ed..c86a29c74 100644 --- a/pkg/providers/gtm/resource_akamai_gtm_datacenter.go +++ b/pkg/providers/gtm/resource_akamai_gtm_datacenter.go @@ -194,7 +194,7 @@ func resourceGTMv1DatacenterCreate(ctx context.Context, d *schema.ResourceData, logger.Errorf("Datacenter Create failed: %s", err.Error()) return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Datacenter Create failed: %s", + Summary: "Datacenter Create failed", Detail: err.Error(), }) } @@ -222,7 +222,7 @@ func resourceGTMv1DatacenterCreate(ctx context.Context, d *schema.ResourceData, logger.Errorf("Datacenter Create failed [%s]", err.Error()) return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Datacenter Create failed: %s", + Summary: "Datacenter Create failed", Detail: err.Error(), }) } diff --git a/pkg/providers/gtm/resource_akamai_gtm_property.go b/pkg/providers/gtm/resource_akamai_gtm_property.go index 29556fcc7..d9e037296 100644 --- a/pkg/providers/gtm/resource_akamai_gtm_property.go +++ b/pkg/providers/gtm/resource_akamai_gtm_property.go @@ -175,7 +175,7 @@ func resourceGTMv1Property() *schema.Resource { }, "traffic_target": { Type: schema.TypeList, - Required: true, + Optional: true, MinItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -364,6 +364,21 @@ func resourceGTMv1PropertyCreate(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } + propertyType, err := tools.GetStringValue("type", d) + if err != nil { + return diag.FromErr(err) + } + // Static properties cannot have traffic_targets. Non Static properties must + traffTargList, err := tools.GetInterfaceArrayValue("traffic_target", d) + if strings.ToUpper(propertyType) == "STATIC" && err == nil && (traffTargList != nil && len(traffTargList) > 0) { + logger.Errorf("Property %s Create failed. Static property cannot have traffic targets", propertyName) + return diag.FromErr(fmt.Errorf("Property Create failed. Static property cannot have traffic targets")) + } + if strings.ToUpper(propertyType) != "STATIC" && (err != nil || (traffTargList == nil || len(traffTargList) < 1)) { + logger.Errorf("Property %s Create failed. Property must have one or more traffic targets", propertyName) + return diag.FromErr(fmt.Errorf("Property Create failed. Property must have one or more traffic targets")) + } + logger.Infof("Creating property [%s] in domain [%s]", propertyName, domain) newProp, err := populateNewPropertyObject(ctx, meta, d, m) if err != nil { @@ -596,9 +611,9 @@ func populatePropertyObject(ctx context.Context, d *schema.ResourceData, prop *g if err == nil { prop.Name = vstr } - vstr, err = tools.GetStringValue("type", d) + ptype, err := tools.GetStringValue("type", d) if err == nil { - prop.Type = vstr + prop.Type = ptype } vstr, err = tools.GetStringValue("score_aggregation_type", d) if err == nil { @@ -794,7 +809,9 @@ func populatePropertyObject(ctx context.Context, d *schema.ResourceData, prop *g return fmt.Errorf("Property Object could not be populated: %v", err.Error()) } - populateTrafficTargetObject(ctx, d, prop, m) + if strings.ToUpper(ptype) != "STATIC" { + populateTrafficTargetObject(ctx, d, prop, m) + } populateStaticRRSetObject(ctx, meta, d, prop) populateLivenessTestObject(ctx, meta, d, prop) @@ -856,7 +873,9 @@ func populateTerraformPropertyState(d *schema.ResourceData, prop *gtm.Property, logger.Errorf("Invalid configuration: %s", err.Error()) } } - populateTerraformTrafficTargetState(d, prop, m) + if strings.ToUpper(prop.Type) != "STATIC" { + populateTerraformTrafficTargetState(d, prop, m) + } populateTerraformStaticRRSetState(d, prop, m) populateTerraformLivenessTestState(d, prop, m) diff --git a/pkg/providers/property/data_akamai_property_rules_schema_v0.go b/pkg/providers/property/data_akamai_property_rules_schema_v0.go index a8122a00b..7d38bca20 100644 --- a/pkg/providers/property/data_akamai_property_rules_schema_v0.go +++ b/pkg/providers/property/data_akamai_property_rules_schema_v0.go @@ -90,7 +90,7 @@ func dataAkamaiPropertyRuleSchemaV0() *schema.Resource { Type: schema.TypeString, Required: true, }, - "comment": { + "comments": { Type: schema.TypeString, Optional: true, }, @@ -110,7 +110,7 @@ func dataAkamaiPropertyRuleSchemaV0() *schema.Resource { Type: schema.TypeString, Required: true, }, - "comment": { + "comments": { Type: schema.TypeString, Optional: true, }, @@ -130,7 +130,7 @@ func dataAkamaiPropertyRuleSchemaV0() *schema.Resource { Type: schema.TypeString, Required: true, }, - "comment": { + "comments": { Type: schema.TypeString, Optional: true, }, @@ -150,7 +150,7 @@ func dataAkamaiPropertyRuleSchemaV0() *schema.Resource { Type: schema.TypeString, Required: true, }, - "comment": { + "comments": { Type: schema.TypeString, Optional: true, }, diff --git a/pkg/providers/property/data_akamai_property_rules_template.go b/pkg/providers/property/data_akamai_property_rules_template.go index 71bad9c92..576ce4c19 100644 --- a/pkg/providers/property/data_akamai_property_rules_template.go +++ b/pkg/providers/property/data_akamai_property_rules_template.go @@ -97,6 +97,16 @@ func dataAkamaiPropertyRulesRead(ctx context.Context, d *schema.ResourceData, m if err != nil { return diag.FromErr(err) } + if _, err := os.Stat(file); err != nil { + if os.IsNotExist(err) { + return diag.FromErr(err) + } + } + dir := filepath.Dir(file) + if filepath.Base(dir) != "property-snippets" || filepath.Ext(file) != ".json" { + logger.Errorf("snippets file should be under 'property-snippets' folder with .json extension: %s", file) + return diag.FromErr(fmt.Errorf("snippets file should be under 'property-snippets' folder with .json extension. Invalid file: %s ", file)) + } varsMap := make(map[string]interface{}) vars, err := tools.GetSetValue("variables", d) if err != nil && !errors.Is(err, tools.ErrNotFound) { @@ -131,7 +141,6 @@ func dataAkamaiPropertyRulesRead(ctx context.Context, d *schema.ResourceData, m if err != nil { return diag.FromErr(err) } - dir := filepath.Dir(file) templateFiles := make(map[string]string) err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { @@ -147,7 +156,18 @@ func dataAkamaiPropertyRulesRead(ctx context.Context, d *schema.ResourceData, m if err != nil { return diag.FromErr(err) } + var diags diag.Diagnostics for name, f := range templateFiles { + b, _ := ioutil.ReadFile(f) + if jsonFileRegexp.MatchString(name) { + var target map[string]interface{} + if err := json.Unmarshal(b, &target); err != nil { + logger.Warnf("invalid JSON result found in template snippet json here %s: ", f) + diags = append(diags, diag.Errorf("invalid JSON result found in template snippet json here %s: %s", f, err)...) + } + } else { + return diag.FromErr(fmt.Errorf("Snippets file under 'property-snippets' folder should have .json files. Invalid file %s ", f)) + } templateStr, err := convertToTemplate(f) if err != nil { return diag.FromErr(err) @@ -157,11 +177,17 @@ func dataAkamaiPropertyRulesRead(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } } + if diags.HasError() { + return diags + } wr := bytes.Buffer{} err = tmpl.ExecuteTemplate(&wr, "main", varsMap) if err != nil { return diag.FromErr(err) } + if !jsonFileRegexp.MatchString(file) { + return diag.FromErr(fmt.Errorf("Snippets file under 'property-snippets' folder should have .json files. Invalid file %s ", file)) + } d.SetId(file) formatted := bytes.Buffer{} result := wr.Bytes() @@ -177,8 +203,9 @@ func dataAkamaiPropertyRulesRead(ctx context.Context, d *schema.ResourceData, m } var ( - includeRegexp = regexp.MustCompile(`"#include:.+"`) - varRegexp = regexp.MustCompile(`"\${.+}"`) + includeRegexp = regexp.MustCompile(`"#include:.+"`) + varRegexp = regexp.MustCompile(`"\${.+}"`) + jsonFileRegexp = regexp.MustCompile(`\.json+$`) ) var ( diff --git a/pkg/providers/property/data_akamai_property_rules_template_test.go b/pkg/providers/property/data_akamai_property_rules_template_test.go index e2e4eb76d..64476454b 100644 --- a/pkg/providers/property/data_akamai_property_rules_template_test.go +++ b/pkg/providers/property/data_akamai_property_rules_template_test.go @@ -138,7 +138,7 @@ func TestDataAkamaiPropertyRulesRead(t *testing.T) { Steps: []resource.TestStep{ { Config: loadFixtureString("testdata/TestDSRulesTemplate/template_invalid_json.tf"), - ExpectError: regexp.MustCompile(`invalid JSON result:`), + ExpectError: regexp.MustCompile(`Error: invalid JSON result found in template snippet json here`), }, }, }) @@ -152,7 +152,66 @@ func TestDataAkamaiPropertyRulesRead(t *testing.T) { Steps: []resource.TestStep{ { Config: loadFixtureString("testdata/TestDSRulesTemplate/template_file_not_found.tf"), - ExpectError: regexp.MustCompile(`template "snippets/not_found.json" not defined`), + ExpectError: regexp.MustCompile(`Error: stat testdata/TestDSRulesTemplate/rules/property-snippets/non-existent.json: no such file or directory`), + }, + }, + }) + }) + }) + t.Run("json has invalid format", func(t *testing.T) { + client := mockpapi{} + useClient(&client, func() { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSRulesTemplate/template_invalid_json.tf"), + ExpectError: regexp.MustCompile(`Error: invalid JSON result found in template snippet json here`), + }, + }, + }) + }) + }) + + t.Run("snippets files are under incorrect folder deeply nested", func(t *testing.T) { + client := mockpapi{} + useClient(&client, func() { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSRulesTemplate/template_invalid_snippets_folder_json.tf"), + ExpectError: regexp.MustCompile(`Error: snippets file should be under 'property-snippets' folder with .json extension. Invalid file: testdata/TestDSRulesTemplate/output/template_invalid_json.json`), + }, + }, + }) + }) + }) + + t.Run("snippets files are under incorrect folder e.g. property-snippets/rules.json", func(t *testing.T) { + client := mockpapi{} + useClient(&client, func() { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSRulesTemplate/template_invalid_snippets_only_one_folder_json.tf"), + ExpectError: regexp.MustCompile(`Error: snippets file should be under 'property-snippets' folder with .json extension. Invalid file: property-snippet/template_invalid_json.json`), + }, + }, + }) + }) + }) + + t.Run("snippets files are non-json invalid error", func(t *testing.T) { + client := mockpapi{} + useClient(&client, func() { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: loadFixtureString("testdata/TestDSRulesTemplate/template_invalid_snippets_file_not_json.tf"), + ExpectError: regexp.MustCompile(`Error: Snippets file under 'property-snippets' folder should have .json files`), }, }, }) @@ -364,7 +423,8 @@ func TestConvertToTypedMap(t *testing.T) { } func TestConvertToTemplate(t *testing.T) { - templates := "testData/TestDSRulesTemplate/rules/templates" + templates := "testData/TestDSRulesTemplate/rules/property-snippets" + templatesOut := "testData/TestDSRulesTemplate/output" tests := map[string]struct { givenFile string expectedFile string @@ -391,7 +451,7 @@ func TestConvertToTemplate(t *testing.T) { return } require.NoError(t, err) - expected := loadFixtureString(fmt.Sprintf("%s/%s", templates, test.expectedFile)) + expected := loadFixtureString(fmt.Sprintf("%s/%s", templatesOut, test.expectedFile)) assert.Equal(t, expected, res) }) } diff --git a/pkg/providers/property/diff_suppress_funcs.go b/pkg/providers/property/diff_suppress_funcs.go index b8a7c0213..8c386024f 100644 --- a/pkg/providers/property/diff_suppress_funcs.go +++ b/pkg/providers/property/diff_suppress_funcs.go @@ -23,6 +23,14 @@ func compareRulesJSON(old, new string) bool { return diff } +func compareRuleTree(old, new *papi.RulesUpdate) bool { + if old.Comments != new.Comments { + return false + } + diff := compareRules(&old.Rules, &new.Rules) + return diff +} + // compareRules handles comparison between two papi.Rules objects // due to an issue in PAPI we need to compare collections of behaviors, criteria and variables discarding the order from JSON func compareRules(old, new *papi.Rules) bool { diff --git a/pkg/providers/property/diff_suppress_funcs_test.go b/pkg/providers/property/diff_suppress_funcs_test.go index 607e03fb5..12d49c2d4 100644 --- a/pkg/providers/property/diff_suppress_funcs_test.go +++ b/pkg/providers/property/diff_suppress_funcs_test.go @@ -28,7 +28,7 @@ func TestCompareRules(t *testing.T) { }, }, Children: []papi.Rules{}, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{ { Locked: "locked", @@ -83,7 +83,7 @@ func TestCompareRules(t *testing.T) { }, }, Children: []papi.Rules{}, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{ { Locked: "locked", @@ -152,7 +152,7 @@ func TestCompareRules(t *testing.T) { }, }, Children: []papi.Rules{}, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{ { Locked: "locked", @@ -217,7 +217,7 @@ func TestCompareRules(t *testing.T) { }, }, Children: []papi.Rules{}, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{ { Locked: "locked", @@ -316,7 +316,7 @@ func TestCompareRules(t *testing.T) { Name: "RULE 2", }, }, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{}, CriteriaLocked: true, CustomOverride: &papi.RuleCustomOverride{ @@ -383,7 +383,7 @@ func TestCompareRules(t *testing.T) { Name: "RULE 2", }, }, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{}, CriteriaLocked: true, CustomOverride: &papi.RuleCustomOverride{ @@ -454,7 +454,7 @@ func TestCompareRules(t *testing.T) { Name: "RULE 1", }, }, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{}, CriteriaLocked: true, CustomOverride: &papi.RuleCustomOverride{ @@ -521,7 +521,7 @@ func TestCompareRules(t *testing.T) { Name: "RULE 2", }, }, - Comment: "comment", + Comments: "comment", Criteria: []papi.RuleBehavior{}, CriteriaLocked: true, CustomOverride: &papi.RuleCustomOverride{ diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_invalid_json.json b/pkg/providers/property/property-snippet/template_invalid_json.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_invalid_json.json rename to pkg/providers/property/property-snippet/template_invalid_json.json diff --git a/pkg/providers/property/resource_akamai_property.go b/pkg/providers/property/resource_akamai_property.go index e3454be60..45e70edc2 100644 --- a/pkg/providers/property/resource_akamai_property.go +++ b/pkg/providers/property/resource_akamai_property.go @@ -63,20 +63,7 @@ func resourceProperty() *schema.Resource { return false } - return compareRules(&oldRules.Rules, &newRules.Rules) - } - - diffSuppressHostNames := func(_, oldHostname, newHostname string, _ *schema.ResourceData) bool { - logger := akamai.Log("PAPI", "suppressRulesJSON") - logger.Debugf("old hostname %v, newhostname %v:", oldHostname, newHostname) - - // There are times where newHostname is comming as Zero. - if newHostname == "0" { - return true - } - - // If oldHostname is not empty and newHostname is empty, the return true (i.e, supress diff). - return oldHostname != "" && newHostname == "" + return compareRuleTree(&oldRules, &newRules) } return &schema.Resource{ @@ -187,11 +174,10 @@ func resourceProperty() *schema.Resource { }, }, "hostnames": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Mapping of edge hostname CNAMEs to other CNAMEs", - DiffSuppressFunc: diffSuppressHostNames, + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Mapping of edge hostname CNAMEs to other CNAMEs", }, // Computed @@ -772,7 +758,10 @@ func fetchPropertyRules(ctx context.Context, client papi.PAPI, Property papi.Pro } logger.WithFields(logFields(*res)).Debug("fetched property rules") - Rules = papi.RulesUpdate{Rules: res.Rules} + Rules = papi.RulesUpdate{ + Rules: res.Rules, + Comments: res.Comments, + } Format = res.RuleFormat Errors = res.Errors Warnings = res.Warnings diff --git a/pkg/providers/property/resource_akamai_property_activation.go b/pkg/providers/property/resource_akamai_property_activation.go index fac5de7dc..4e259a83a 100644 --- a/pkg/providers/property/resource_akamai_property_activation.go +++ b/pkg/providers/property/resource_akamai_property_activation.go @@ -134,6 +134,7 @@ func resourcePropertyActivationCreate(ctx context.Context, d *schema.ResourceDat ValidateRules: true, }) if err != nil { + d.Partial(true) return diag.FromErr(err) } @@ -532,6 +533,8 @@ func resourcePropertyActivationUpdate(ctx context.Context, d *schema.ResourceDat ValidateRules: true, }) if err != nil { + // Reverting to previous state(property version in this case) when error occurs. + d.Partial(true) return diag.FromErr(err) } diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/plain_json.json b/pkg/providers/property/testdata/TestDSRulesTemplate/output/plain_json.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/plain_json.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/output/plain_json.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/sub/some-template.tmpl b/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/sub/some-template.tmpl new file mode 100644 index 000000000..6b7f8497d --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/sub/some-template.tmpl @@ -0,0 +1 @@ +invalid json \ No newline at end of file diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/template_invalid_json.json b/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/template_invalid_json.json new file mode 100644 index 000000000..b735f877d --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/output/property-snippets/template_invalid_json.json @@ -0,0 +1,8 @@ +{ + "rules": { + "name": "${env.name}", + "children": [ + "#include:snippets/sub/some-template.tmpl" + ] + } +} \ No newline at end of file diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/output/template_invalid_json.json b/pkg/providers/property/testdata/TestDSRulesTemplate/output/template_invalid_json.json new file mode 100644 index 000000000..6b7f8497d --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/output/template_invalid_json.json @@ -0,0 +1 @@ +invalid json \ No newline at end of file diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_out.json b/pkg/providers/property/testdata/TestDSRulesTemplate/output/template_out.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_out.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/output/template_out.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_invalid_json.json b/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_invalid_json.json new file mode 100644 index 000000000..6b7f8497d --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_invalid_json.json @@ -0,0 +1 @@ +invalid json \ No newline at end of file diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_out.json b/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_out.json new file mode 100644 index 000000000..ad321cfda --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/property-snippets/template_out.json @@ -0,0 +1,8 @@ +{ + "rules": { + "name": @+#.name#+@, + "children": [ + @+#template "snippets/some-template.json" .#+@ + ] + } +} diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/plain_json.json b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/plain_json.json new file mode 100644 index 000000000..c3dad8015 --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/plain_json.json @@ -0,0 +1,27 @@ +{ + "rules": { + "name": "test", + "children": [ + { + "name": "RUM", + "children": [ + ], + "behaviors": [ + { + "name": "mPulse", + "options": { + "enabled": true, + "requirePci": false, + "titleOptional": "", + "apiKey": "", + "bufferSize": "", + "configOverride": "" + } + } + ], + "criteria": [], + "criteriaMustSatisfy": "all" + } + ] + } +} diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/snippets/some-template.json b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/snippets/some-template.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/snippets/some-template.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/snippets/some-template.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/snippets/sub/another-template.json b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/snippets/sub/another-template.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/snippets/sub/another-template.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/snippets/sub/another-template.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_file_not_found.json b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/template_file_not_found.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_file_not_found.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/template_file_not_found.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_in.json b/pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json similarity index 100% rename from pkg/providers/property/testdata/TestDSRulesTemplate/rules/templates/template_in.json rename to pkg/providers/property/testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_file_not_found.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_file_not_found.tf index ad4a6490f..70582b43a 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_file_not_found.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_file_not_found.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_file_not_found.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/non-existent.json" variables { name = "criteriaMustSatisfy" value = "all" diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_json.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_json.tf index 6bdfa75d3..fe5d0b141 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_json.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_json.tf @@ -3,5 +3,5 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_invalid_json.json" + template_file = "testdata/TestDSRulesTemplate/property-snippets/template_invalid_json.json" } diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_file_not_json.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_file_not_json.tf new file mode 100644 index 000000000..75baad3e7 --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_file_not_json.tf @@ -0,0 +1,7 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_property_rules_template" "test" { + template_file = "testdata/TestDSRulesTemplate/output/property-snippets/template_invalid_json.json" +} diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_folder_json.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_folder_json.tf new file mode 100644 index 000000000..294b2b927 --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_folder_json.tf @@ -0,0 +1,7 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_property_rules_template" "test" { + template_file = "testdata/TestDSRulesTemplate/output/template_invalid_json.json" +} diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_only_one_folder_json.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_only_one_folder_json.tf new file mode 100644 index 000000000..9570f7e58 --- /dev/null +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_invalid_snippets_only_one_folder_json.tf @@ -0,0 +1,7 @@ +provider "akamai" { + edgerc = "~/.edgerc" +} + +data "akamai_property_rules_template" "test" { + template_file = "property-snippet/template_invalid_json.json" +} diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_null_values.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_null_values.tf index 0ac3154f6..c8a2059fd 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_null_values.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_null_values.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" var_definition_file = "testdata/TestDSRulesTemplate/rules/variables/variableDefinitions.json" var_values_file = "testdata/TestDSRulesTemplate/rules/variables/null_values.json" } diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_var_not_found.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_var_not_found.tf index 72a29716c..0765bcdbf 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_var_not_found.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_var_not_found.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" variables { name = "criteriaMustSatisfy" value = "all" diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_conflict.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_conflict.tf index 03fe38b48..ad08edb65 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_conflict.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_conflict.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" var_definition_file = "testdata/TestDSRulesTemplate/rules/variables/variableDefinitions.json" var_values_file = "testdata/TestDSRulesTemplate/rules/variables/variables.json" variables { diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file.tf index b972bb02b..b1c507843 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" var_definition_file = "testdata/TestDSRulesTemplate/rules/variables/variableDefinitions.json" var_values_file = "testdata/TestDSRulesTemplate/rules/variables/variables.json" } diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file_not_found.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file_not_found.tf index 7dc98306a..1770b528d 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file_not_found.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_file_not_found.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" var_definition_file = "invalid_path" var_values_file = "testdata/TestDSRulesTemplate/rules/variables/variables.json" } diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_type.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_type.tf index 9e535a6bf..ac654eb40 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_type.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_type.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" variables { name = "criteriaMustSatisfy" value = "all" diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_value.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_value.tf index 1ecbc2d6f..9d0395abd 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_value.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_invalid_value.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" variables { name = "criteriaMustSatisfy" value = "all" diff --git a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_map.tf b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_map.tf index 975295ad3..4c3132802 100644 --- a/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_map.tf +++ b/pkg/providers/property/testdata/TestDSRulesTemplate/template_vars_map.tf @@ -3,7 +3,7 @@ provider "akamai" { } data "akamai_property_rules_template" "test" { - template_file = "testdata/TestDSRulesTemplate/rules/templates/template_in.json" + template_file = "testdata/TestDSRulesTemplate/rules/property-snippets/template_in.json" variables { name = "criteriaMustSatisfy" value = "all"