diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58db1f22..9bff39cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
- Add `sdwan_cisco_secure_internet_gateway_feature_template` resource and data source
- Add `sdwan_hub_and_spoke_topology_policy_definition` resource and data source
- Add `sdwan_mesh_topology_policy_definition` resource and data source
+- Add `sdwan_custom_control_topology_policy_definition` resource and data source
## 0.2.0
diff --git a/docs/data-sources/custom_control_topology_policy_definition.md b/docs/data-sources/custom_control_topology_policy_definition.md
new file mode 100644
index 00000000..9c37cbf6
--- /dev/null
+++ b/docs/data-sources/custom_control_topology_policy_definition.md
@@ -0,0 +1,117 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "sdwan_custom_control_topology_policy_definition Data Source - terraform-provider-sdwan"
+subcategory: "Centralized Policies"
+description: |-
+ This data source can read the Custom Control Topology policy definition.
+---
+
+# sdwan_custom_control_topology_policy_definition (Data Source)
+
+This data source can read the Custom Control Topology policy definition.
+
+## Example Usage
+
+```terraform
+data "sdwan_custom_control_topology_policy_definition" "example" {
+ id = "f6b2c44c-693c-4763-b010-895aa3d236bd"
+}
+```
+
+
+## Schema
+
+### Required
+
+- `id` (String) The id of the policy definition
+
+### Read-Only
+
+- `default_action` (String) Default action, either `accept` or `reject`
+- `description` (String) The description of the policy definition
+- `name` (String) The name of the policy definition
+- `sequences` (Attributes List) List of sequences (see [below for nested schema](#nestedatt--sequences))
+- `type` (String) The policy definition type
+- `version` (Number) The version of the policy definition
+
+
+### Nested Schema for `sequences`
+
+Read-Only:
+
+- `action_entries` (Attributes List) List of action entries (see [below for nested schema](#nestedatt--sequences--action_entries))
+- `id` (Number) Sequence ID
+- `ip_type` (String) Sequence IP type, either `ipv4`, `ipv6` or `all`
+- `match_entries` (Attributes List) List of match entries (see [below for nested schema](#nestedatt--sequences--match_entries))
+- `name` (String) Sequence name
+- `type` (String) Sequence type, either `route` or `tloc`
+
+
+### Nested Schema for `sequences.action_entries`
+
+Read-Only:
+
+- `export_to_vpn_list_id` (String) Export to VPN list ID
+- `export_to_vpn_list_version` (Number) Export to VPN list version
+- `set_parameters` (Attributes List) List of set parameters (see [below for nested schema](#nestedatt--sequences--action_entries--set_parameters))
+- `type` (String) Type of action entry
+
+
+### Nested Schema for `sequences.action_entries.set_parameters`
+
+Read-Only:
+
+- `community` (String) Community value, e.g. `1000:10000` or `internet` or `local-AS`
+- `community_additive` (Boolean) Community additive
+- `omp_tag` (Number) OMP tag
+- `preference` (Number) Preference
+- `service_tloc_color` (String) Service TLOC color
+- `service_tloc_encapsulation` (String) Service TLOC encapsulation
+- `service_tloc_ip` (String) Service TLOC IP address
+- `service_tloc_list_id` (String) Service TLOC list ID
+- `service_tloc_list_version` (Number) Service TLOC list version
+- `service_type` (String) Service type
+- `service_vpn_id` (Number) Service VPN ID
+- `tloc_action` (String) TLOC action
+- `tloc_color` (String) TLOC color
+- `tloc_encapsulation` (String) TLOC encapsulation
+- `tloc_ip` (String) TLOC IP address
+- `tloc_list_id` (String) TLOC list ID
+- `tloc_list_version` (Number) TLOC list version
+- `type` (String) Type of action entry
+
+
+
+
+### Nested Schema for `sequences.match_entries`
+
+Read-Only:
+
+- `carrier` (String) Carrier
+- `color_list_id` (String) Color list ID
+- `color_list_version` (Number) Color list version
+- `community_list_id` (String) Community list ID
+- `community_list_version` (Number) Community list version
+- `domain_id` (Number) Domain ID
+- `expanded_community_list_id` (String) Expanded community list ID
+- `expanded_community_list_version` (Number) Expanded community list version
+- `group_id` (Number) Group ID
+- `omp_tag` (Number) OMP tag
+- `origin` (String) Origin
+- `originator` (String) Originator IP
+- `path_type` (String) Path type
+- `preference` (Number) Preference
+- `prefix_list_id` (String) Prefix list ID
+- `prefix_list_version` (Number) Prefix list version
+- `site_id` (Number) Site ID
+- `site_list_id` (String) Site list ID
+- `site_list_version` (Number) Site list version
+- `tloc_color` (String) TLOC color
+- `tloc_encapsulation` (String) TLOC encapsulation
+- `tloc_ip` (String) TLOC IP address
+- `tloc_list_id` (String) TLOC list ID
+- `tloc_list_version` (Number) TLOC list version
+- `type` (String) Type of match entry
+- `vpn_id` (Number) VPN ID
+- `vpn_list_id` (String) VPN list ID
+- `vpn_list_version` (Number) VPN list version
diff --git a/docs/guides/changelog.md b/docs/guides/changelog.md
index 8f5fe6b8..8f43c441 100644
--- a/docs/guides/changelog.md
+++ b/docs/guides/changelog.md
@@ -14,6 +14,7 @@ description: |-
- Add `sdwan_cisco_secure_internet_gateway_feature_template` resource and data source
- Add `sdwan_hub_and_spoke_topology_policy_definition` resource and data source
- Add `sdwan_mesh_topology_policy_definition` resource and data source
+- Add `sdwan_custom_control_topology_policy_definition` resource and data source
## 0.2.0
diff --git a/docs/resources/custom_control_topology_policy_definition.md b/docs/resources/custom_control_topology_policy_definition.md
new file mode 100644
index 00000000..ce800f06
--- /dev/null
+++ b/docs/resources/custom_control_topology_policy_definition.md
@@ -0,0 +1,190 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "sdwan_custom_control_topology_policy_definition Resource - terraform-provider-sdwan"
+subcategory: "Centralized Policies"
+description: |-
+ This resource can manage a Custom Control Topology policy definition.
+---
+
+# sdwan_custom_control_topology_policy_definition (Resource)
+
+This resource can manage a Custom Control Topology policy definition.
+
+## Example Usage
+
+```terraform
+resource "sdwan_custom_control_topology_policy_definition" "example" {
+ name = "Example"
+ description = "My description"
+ default_action = "reject"
+ sequences = [
+ {
+ id = 1
+ name = "Region1"
+ type = "route"
+ ip_type = "ipv4"
+ match_entries = [
+ {
+ type = "ompTag"
+ omp_tag = 100
+ }
+ ]
+ action_entries = [
+ {
+ type = "set"
+ set_parameters = [
+ {
+ type = "preference"
+ preference = 100
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+```
+
+
+## Schema
+
+### Required
+
+- `description` (String) The description of the policy definition
+- `name` (String) The name of the policy definition
+- `sequences` (Attributes List) List of sequences (see [below for nested schema](#nestedatt--sequences))
+
+### Optional
+
+- `default_action` (String) Default action, either `accept` or `reject`
+ - Choices: `accept`, `reject`
+
+### Read-Only
+
+- `id` (String) The id of the policy definition
+- `type` (String) The policy defintion type
+- `version` (Number) The version of the policy definition
+
+
+### Nested Schema for `sequences`
+
+Required:
+
+- `id` (Number) Sequence ID
+- `name` (String) Sequence name
+
+Optional:
+
+- `action_entries` (Attributes List) List of action entries (see [below for nested schema](#nestedatt--sequences--action_entries))
+- `ip_type` (String) Sequence IP type, either `ipv4`, `ipv6` or `all`
+ - Choices: `ipv4`, `ipv6`, `all`
+- `match_entries` (Attributes List) List of match entries (see [below for nested schema](#nestedatt--sequences--match_entries))
+- `type` (String) Sequence type, either `route` or `tloc`
+ - Choices: `route`, `tloc`
+
+
+### Nested Schema for `sequences.action_entries`
+
+Required:
+
+- `type` (String) Type of action entry
+ - Choices: `set`, `exportTo`
+
+Optional:
+
+- `export_to_vpn_list_id` (String) Export to VPN list ID
+- `export_to_vpn_list_version` (Number) Export to VPN list version
+- `set_parameters` (Attributes List) List of set parameters (see [below for nested schema](#nestedatt--sequences--action_entries--set_parameters))
+
+
+### Nested Schema for `sequences.action_entries.set_parameters`
+
+Required:
+
+- `type` (String) Type of action entry
+ - Choices: `tlocList`, `tloc`, `tlocAction`, `preference`, `ompTag`, `community`, `communityAdditive`, `service`
+
+Optional:
+
+- `community` (String) Community value, e.g. `1000:10000` or `internet` or `local-AS`
+- `community_additive` (Boolean) Community additive
+- `omp_tag` (Number) OMP tag
+ - Range: `0`-`4294967295`
+- `preference` (Number) Preference
+ - Range: `0`-`4294967295`
+- `service_tloc_color` (String) Service TLOC color
+- `service_tloc_encapsulation` (String) Service TLOC encapsulation
+ - Choices: `ipsec`, `gre`
+- `service_tloc_ip` (String) Service TLOC IP address
+- `service_tloc_list_id` (String) Service TLOC list ID
+- `service_tloc_list_version` (Number) Service TLOC list version
+- `service_type` (String) Service type
+ - Choices: `FW`, `IDP`, `IDS`, `netsvc1`, `netsvc2`, `netsvc3`, `netsvc4`, `netsvc5`
+- `service_vpn_id` (Number) Service VPN ID
+ - Range: `0`-`65536`
+- `tloc_action` (String) TLOC action
+ - Choices: `strict`, `primary`, `backup`, `ecmp`
+- `tloc_color` (String) TLOC color
+- `tloc_encapsulation` (String) TLOC encapsulation
+ - Choices: `ipsec`, `gre`
+- `tloc_ip` (String) TLOC IP address
+- `tloc_list_id` (String) TLOC list ID
+- `tloc_list_version` (Number) TLOC list version
+
+
+
+
+### Nested Schema for `sequences.match_entries`
+
+Required:
+
+- `type` (String) Type of match entry
+ - Choices: `colorList`, `community`, `expandedCommunity`, `ompTag`, `origin`, `originator`, `preference`, `siteList`, `pathType`, `tlocList`, `vpnList`, `prefixList`, `vpn`, `tloc`, `siteId`, `carrier`, `domainId`, `groupId`
+
+Optional:
+
+- `carrier` (String) Carrier
+ - Choices: `default`, `carrier1`, `carrier2`, `carrier3`, `carrier4`, `carrier5`, `carrier6`, `carrier7`, `carrier8`
+- `color_list_id` (String) Color list ID
+- `color_list_version` (Number) Color list version
+- `community_list_id` (String) Community list ID
+- `community_list_version` (Number) Community list version
+- `domain_id` (Number) Domain ID
+ - Range: `0`-`4294967295`
+- `expanded_community_list_id` (String) Expanded community list ID
+- `expanded_community_list_version` (Number) Expanded community list version
+- `group_id` (Number) Group ID
+ - Range: `0`-`4294967295`
+- `omp_tag` (Number) OMP tag
+ - Range: `0`-`4294967295`
+- `origin` (String) Origin
+ - Choices: `igp`, `egp`, `incomplete`
+- `originator` (String) Originator IP
+- `path_type` (String) Path type
+ - Choices: `hierarchical-path`, `direct-path`, `transport-gateway-path`
+- `preference` (Number) Preference
+ - Range: `0`-`4294967295`
+- `prefix_list_id` (String) Prefix list ID
+- `prefix_list_version` (Number) Prefix list version
+- `site_id` (Number) Site ID
+ - Range: `0`-`4294967295`
+- `site_list_id` (String) Site list ID
+- `site_list_version` (Number) Site list version
+- `tloc_color` (String) TLOC color
+- `tloc_encapsulation` (String) TLOC encapsulation
+ - Choices: `ipsec`, `gre`
+- `tloc_ip` (String) TLOC IP address
+- `tloc_list_id` (String) TLOC list ID
+- `tloc_list_version` (Number) TLOC list version
+- `vpn_id` (Number) VPN ID
+ - Range: `0`-`65536`
+- `vpn_list_id` (String) VPN list ID
+- `vpn_list_version` (Number) VPN list version
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import sdwan_custom_control_topology_policy_definition.example "f6b2c44c-693c-4763-b010-895aa3d236bd"
+```
diff --git a/examples/data-sources/sdwan_custom_control_topology_policy_definition/data-source.tf b/examples/data-sources/sdwan_custom_control_topology_policy_definition/data-source.tf
new file mode 100644
index 00000000..39a2ec74
--- /dev/null
+++ b/examples/data-sources/sdwan_custom_control_topology_policy_definition/data-source.tf
@@ -0,0 +1,3 @@
+data "sdwan_custom_control_topology_policy_definition" "example" {
+ id = "f6b2c44c-693c-4763-b010-895aa3d236bd"
+}
diff --git a/examples/resources/sdwan_custom_control_topology_policy_definition/import.sh b/examples/resources/sdwan_custom_control_topology_policy_definition/import.sh
new file mode 100644
index 00000000..638b4a70
--- /dev/null
+++ b/examples/resources/sdwan_custom_control_topology_policy_definition/import.sh
@@ -0,0 +1 @@
+terraform import sdwan_custom_control_topology_policy_definition.example "f6b2c44c-693c-4763-b010-895aa3d236bd"
diff --git a/examples/resources/sdwan_custom_control_topology_policy_definition/resource.tf b/examples/resources/sdwan_custom_control_topology_policy_definition/resource.tf
new file mode 100644
index 00000000..ec1baab7
--- /dev/null
+++ b/examples/resources/sdwan_custom_control_topology_policy_definition/resource.tf
@@ -0,0 +1,30 @@
+resource "sdwan_custom_control_topology_policy_definition" "example" {
+ name = "Example"
+ description = "My description"
+ default_action = "reject"
+ sequences = [
+ {
+ id = 1
+ name = "Region1"
+ type = "route"
+ ip_type = "ipv4"
+ match_entries = [
+ {
+ type = "ompTag"
+ omp_tag = 100
+ }
+ ]
+ action_entries = [
+ {
+ type = "set"
+ set_parameters = [
+ {
+ type = "preference"
+ preference = 100
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/gen/definitions/policy_definitions/custom_control_topology.yaml b/gen/definitions/policy_definitions/custom_control_topology.yaml
new file mode 100644
index 00000000..b2ee4f18
--- /dev/null
+++ b/gen/definitions/policy_definitions/custom_control_topology.yaml
@@ -0,0 +1,436 @@
+---
+name: Custom Control Topology
+type: control
+doc_category: Centralized Policies
+skip_templates: [model.go, resource.go, data_source.go]
+attributes:
+ - model_name: type
+ tf_name: default_action
+ data_path: [defaultAction]
+ type: String
+ enum_values: [accept, reject]
+ description: Default action, either `accept` or `reject`
+ example: reject
+ - model_name: sequences
+ tf_name: sequences
+ type: List
+ mandatory: true
+ description: List of sequences
+ attributes:
+ - model_name: sequenceId
+ tf_name: id
+ type: Int64
+ mandatory: true
+ description: Sequence ID
+ example: 1
+ - model_name: sequenceName
+ tf_name: name
+ type: String
+ mandatory: true
+ description: Sequence name
+ example: Region1
+ - model_name: sequenceType
+ tf_name: type
+ type: String
+ enum_values: [route, tloc]
+ description: Sequence type, either `route` or `tloc`
+ example: route
+ - model_name: sequenceIpType
+ tf_name: ip_type
+ type: String
+ enum_values: [ipv4, ipv6, all]
+ description: Sequence IP type, either `ipv4`, `ipv6` or `all`
+ example: ipv4
+ - model_name: entries
+ data_path: [match]
+ tf_name: match_entries
+ type: List
+ description: List of match entries
+ attributes:
+ - model_name: field
+ tf_name: type
+ type: String
+ mandatory: true
+ enum_values:
+ [
+ colorList,
+ community,
+ expandedCommunity,
+ ompTag,
+ origin,
+ originator,
+ preference,
+ siteList,
+ pathType,
+ tlocList,
+ vpnList,
+ prefixList,
+ vpn,
+ tloc,
+ siteId,
+ carrier,
+ domainId,
+ groupId,
+ ]
+ description: Type of match entry
+ example: ompTag
+ - model_name: ref
+ tf_name: color_list_id
+ type: String
+ description: Color list ID
+ example: 0bfee1b7-1ac5-4ee3-bebc-61af04792e7c
+ exclude_test: true
+ - tf_name: color_list_version
+ tf_only: true
+ type: Int64
+ description: Color list version
+ exclude_test: true
+ - model_name: ref
+ tf_name: community_list_id
+ type: String
+ description: Community list ID
+ example: 8bca4de4-78c7-4a44-9a55-5d4f3195cfe9
+ exclude_test: true
+ - tf_name: community_list_version
+ tf_only: true
+ type: Int64
+ description: Community list version
+ exclude_test: true
+ - model_name: ref
+ tf_name: expanded_community_list_id
+ type: String
+ description: Expanded community list ID
+ example: f57a0c33-c6f8-4b07-ac92-d9a22ade9bb8
+ exclude_test: true
+ - tf_name: expanded_community_list_version
+ tf_only: true
+ type: Int64
+ description: Expanded community list version
+ exclude_test: true
+ - model_name: value
+ tf_name: omp_tag
+ type: Int64
+ model_type_string: true
+ description: OMP tag
+ min_int: 0
+ max_int: 4294967295
+ example: 100
+ - model_name: value
+ tf_name: origin
+ type: String
+ enum_values: [igp, egp, incomplete]
+ description: Origin
+ example: igp
+ exclude_test: true
+ - model_name: value
+ tf_name: originator
+ type: String
+ description: Originator IP
+ example: 1.2.3.4
+ exclude_test: true
+ - model_name: value
+ tf_name: preference
+ type: Int64
+ model_type_string: true
+ description: Preference
+ min_int: 0
+ max_int: 4294967295
+ example: 100
+ exclude_test: true
+ - model_name: ref
+ tf_name: site_list_id
+ type: String
+ description: Site list ID
+ example: e858e1c4-6aa8-4de7-99df-c3adbf80290d
+ exclude_test: true
+ - tf_name: site_list_version
+ tf_only: true
+ type: Int64
+ description: Site list version
+ exclude_test: true
+ - model_name: value
+ tf_name: path_type
+ type: String
+ enum_values:
+ [hierarchical-path, direct-path, transport-gateway-path]
+ description: Path type
+ example: hierarchical-path
+ exclude_test: true
+ - model_name: ref
+ tf_name: tloc_list_id
+ type: String
+ description: TLOC list ID
+ example: 8b249706-7c7f-4ab3-af6f-c91951c1a603
+ exclude_test: true
+ - tf_name: tloc_list_version
+ tf_only: true
+ type: Int64
+ description: TLOC list version
+ exclude_test: true
+ - model_name: ref
+ tf_name: vpn_list_id
+ type: String
+ description: VPN list ID
+ example: 04fcbb0b-efbf-43d2-a04b-847d3a7b104e
+ exclude_test: true
+ - tf_name: vpn_list_version
+ tf_only: true
+ type: Int64
+ description: VPN list version
+ exclude_test: true
+ - model_name: ref
+ tf_name: prefix_list_id
+ type: String
+ description: Prefix list ID
+ example: 3639191a-246a-4023-bbe3-658eec3bf2ab
+ exclude_test: true
+ - tf_name: prefix_list_version
+ tf_only: true
+ type: Int64
+ description: Prefix list version
+ exclude_test: true
+ - model_name: value
+ tf_name: vpn_id
+ type: Int64
+ model_type_string: true
+ description: VPN ID
+ min_int: 0
+ max_int: 65536
+ example: 123
+ exclude_test: true
+ - model_name: ip
+ data_path: [value]
+ tf_name: tloc_ip
+ type: String
+ description: TLOC IP address
+ example: 1.2.3.4
+ exclude_test: true
+ - model_name: color
+ data_path: [value]
+ tf_name: tloc_color
+ type: String
+ description: TLOC color
+ example: bronze
+ exclude_test: true
+ - model_name: encap
+ data_path: [value]
+ tf_name: tloc_encapsulation
+ type: String
+ enum_values: [ipsec, gre]
+ description: TLOC encapsulation
+ example: ipsec
+ exclude_test: true
+ - model_name: value
+ tf_name: site_id
+ type: Int64
+ model_type_string: true
+ description: Site ID
+ min_int: 0
+ max_int: 4294967295
+ example: 123
+ exclude_test: true
+ - model_name: value
+ tf_name: carrier
+ type: String
+ enum_values:
+ [
+ default,
+ carrier1,
+ carrier2,
+ carrier3,
+ carrier4,
+ carrier5,
+ carrier6,
+ carrier7,
+ carrier8,
+ ]
+ description: Carrier
+ example: carrier1
+ exclude_test: true
+ - model_name: value
+ tf_name: domain_id
+ type: Int64
+ model_type_string: true
+ description: Domain ID
+ min_int: 0
+ max_int: 4294967295
+ example: 123
+ exclude_test: true
+ - model_name: value
+ tf_name: group_id
+ type: Int64
+ model_type_string: true
+ description: Group ID
+ min_int: 0
+ max_int: 4294967295
+ example: 1
+ exclude_test: true
+ - model_name: actions
+ tf_name: action_entries
+ type: List
+ description: List of action entries
+ attributes:
+ - model_name: type
+ tf_name: type
+ type: String
+ mandatory: true
+ enum_values: [set, exportTo]
+ description: Type of action entry
+ example: set
+ - model_name: parameter
+ tf_name: set_parameters
+ type: List
+ description: List of set parameters
+ attributes:
+ - model_name: field
+ tf_name: type
+ type: String
+ mandatory: true
+ enum_values:
+ [
+ tlocList,
+ tloc,
+ tlocAction,
+ preference,
+ ompTag,
+ community,
+ communityAdditive,
+ service,
+ ]
+ description: Type of action entry
+ example: preference
+ - model_name: ref
+ tf_name: tloc_list_id
+ type: String
+ description: TLOC list ID
+ example: 8b249706-7c7f-4ab3-af6f-c91951c1a603
+ exclude_test: true
+ - tf_name: tloc_list_version
+ tf_only: true
+ type: Int64
+ description: TLOC list version
+ exclude_test: true
+ - model_name: ip
+ data_path: [value]
+ tf_name: tloc_ip
+ type: String
+ description: TLOC IP address
+ example: 1.2.3.4
+ exclude_test: true
+ - model_name: color
+ data_path: [value]
+ tf_name: tloc_color
+ type: String
+ description: TLOC color
+ example: bronze
+ exclude_test: true
+ - model_name: encap
+ data_path: [value]
+ tf_name: tloc_encapsulation
+ type: String
+ enum_values: [ipsec, gre]
+ description: TLOC encapsulation
+ example: ipsec
+ exclude_test: true
+ - model_name: value
+ tf_name: tloc_action
+ type: String
+ enum_values: [strict, primary, backup, ecmp]
+ description: TLOC action
+ example: strict
+ exclude_test: true
+ - model_name: value
+ tf_name: preference
+ type: Int64
+ model_type_string: true
+ description: Preference
+ min_int: 0
+ max_int: 4294967295
+ example: 100
+ - model_name: value
+ tf_name: omp_tag
+ type: Int64
+ model_type_string: true
+ description: OMP tag
+ min_int: 0
+ max_int: 4294967295
+ example: 100
+ exclude_test: true
+ - model_name: value
+ tf_name: community
+ type: String
+ description: Community value, e.g. `1000:10000` or `internet` or `local-AS`
+ example: 1000:10000
+ exclude_test: true
+ - model_name: value
+ tf_name: community_additive
+ type: Bool
+ model_type_string: true
+ description: Community additive
+ example: true
+ exclude_test: true
+ - model_name: type
+ data_path: [value]
+ tf_name: service_type
+ type: String
+ enum_values:
+ [FW, IDP, IDS, netsvc1, netsvc2, netsvc3, netsvc4, netsvc5]
+ description: Service type
+ example: IDP
+ exclude_test: true
+ - model_name: vpn
+ data_path: [value]
+ tf_name: service_vpn_id
+ type: Int64
+ model_type_string: true
+ description: Service VPN ID
+ min_int: 0
+ max_int: 65536
+ example: 100
+ exclude_test: true
+ - model_name: tlocList
+ data_path: [value]
+ tf_name: service_tloc_list_id
+ type: String
+ description: Service TLOC list ID
+ example: 8b249706-7c7f-4ab3-af6f-c91951c1a603
+ exclude_test: true
+ - tf_name: service_tloc_list_version
+ tf_only: true
+ type: Int64
+ description: Service TLOC list version
+ exclude_test: true
+ - model_name: ip
+ data_path: [value, tloc]
+ tf_name: service_tloc_ip
+ type: String
+ description: Service TLOC IP address
+ example: 1.2.3.4
+ exclude_test: true
+ - model_name: color
+ data_path: [value, tloc]
+ tf_name: service_tloc_color
+ type: String
+ description: Service TLOC color
+ example: bronze
+ exclude_test: true
+ - model_name: encap
+ data_path: [value, tloc]
+ tf_name: service_tloc_encapsulation
+ type: String
+ enum_values: [ipsec, gre]
+ description: Service TLOC encapsulation
+ example: ipsec
+ exclude_test: true
+ - model_name: ref
+ data_path: [parameter]
+ tf_name: export_to_vpn_list_id
+ type: String
+ description: Export to VPN list ID
+ example: 04fcbb0b-efbf-43d2-a04b-847d3a7b104e
+ exclude_test: true
+ - tf_name: export_to_vpn_list_version
+ tf_only: true
+ type: Int64
+ description: Export to VPN list version
+ exclude_test: true
diff --git a/internal/provider/data_source_sdwan_custom_control_topology_policy_definition.go b/internal/provider/data_source_sdwan_custom_control_topology_policy_definition.go
new file mode 100644
index 00000000..f0f97231
--- /dev/null
+++ b/internal/provider/data_source_sdwan_custom_control_topology_policy_definition.go
@@ -0,0 +1,361 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by "gen/generator.go"; DO NOT EDIT.
+
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/netascode/go-sdwan"
+)
+
+// Ensure the implementation satisfies the expected interfaces.
+var (
+ _ datasource.DataSource = &CustomControlTopologyPolicyDefinitionDataSource{}
+ _ datasource.DataSourceWithConfigure = &CustomControlTopologyPolicyDefinitionDataSource{}
+)
+
+func NewCustomControlTopologyPolicyDefinitionDataSource() datasource.DataSource {
+ return &CustomControlTopologyPolicyDefinitionDataSource{}
+}
+
+type CustomControlTopologyPolicyDefinitionDataSource struct {
+ client *sdwan.Client
+}
+
+func (d *CustomControlTopologyPolicyDefinitionDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_custom_control_topology_policy_definition"
+}
+
+func (d *CustomControlTopologyPolicyDefinitionDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ // This description is used by the documentation generator and the language server.
+ MarkdownDescription: "This data source can read the Custom Control Topology policy definition.",
+
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ MarkdownDescription: "The id of the policy definition",
+ Required: true,
+ },
+ "version": schema.Int64Attribute{
+ MarkdownDescription: "The version of the policy definition",
+ Computed: true,
+ },
+ "type": schema.StringAttribute{
+ MarkdownDescription: "The policy definition type",
+ Computed: true,
+ },
+ "name": schema.StringAttribute{
+ MarkdownDescription: "The name of the policy definition",
+ Computed: true,
+ },
+ "description": schema.StringAttribute{
+ MarkdownDescription: "The description of the policy definition",
+ Computed: true,
+ },
+ "default_action": schema.StringAttribute{
+ MarkdownDescription: "Default action, either `accept` or `reject`",
+ Computed: true,
+ },
+ "sequences": schema.ListNestedAttribute{
+ MarkdownDescription: "List of sequences",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.Int64Attribute{
+ MarkdownDescription: "Sequence ID",
+ Computed: true,
+ },
+ "name": schema.StringAttribute{
+ MarkdownDescription: "Sequence name",
+ Computed: true,
+ },
+ "type": schema.StringAttribute{
+ MarkdownDescription: "Sequence type, either `route` or `tloc`",
+ Computed: true,
+ },
+ "ip_type": schema.StringAttribute{
+ MarkdownDescription: "Sequence IP type, either `ipv4`, `ipv6` or `all`",
+ Computed: true,
+ },
+ "match_entries": schema.ListNestedAttribute{
+ MarkdownDescription: "List of match entries",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: "Type of match entry",
+ Computed: true,
+ },
+ "color_list_id": schema.StringAttribute{
+ MarkdownDescription: "Color list ID",
+ Computed: true,
+ },
+ "color_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Color list version",
+ Computed: true,
+ },
+ "community_list_id": schema.StringAttribute{
+ MarkdownDescription: "Community list ID",
+ Computed: true,
+ },
+ "community_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Community list version",
+ Computed: true,
+ },
+ "expanded_community_list_id": schema.StringAttribute{
+ MarkdownDescription: "Expanded community list ID",
+ Computed: true,
+ },
+ "expanded_community_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Expanded community list version",
+ Computed: true,
+ },
+ "omp_tag": schema.Int64Attribute{
+ MarkdownDescription: "OMP tag",
+ Computed: true,
+ },
+ "origin": schema.StringAttribute{
+ MarkdownDescription: "Origin",
+ Computed: true,
+ },
+ "originator": schema.StringAttribute{
+ MarkdownDescription: "Originator IP",
+ Computed: true,
+ },
+ "preference": schema.Int64Attribute{
+ MarkdownDescription: "Preference",
+ Computed: true,
+ },
+ "site_list_id": schema.StringAttribute{
+ MarkdownDescription: "Site list ID",
+ Computed: true,
+ },
+ "site_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Site list version",
+ Computed: true,
+ },
+ "path_type": schema.StringAttribute{
+ MarkdownDescription: "Path type",
+ Computed: true,
+ },
+ "tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: "TLOC list ID",
+ Computed: true,
+ },
+ "tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: "TLOC list version",
+ Computed: true,
+ },
+ "vpn_list_id": schema.StringAttribute{
+ MarkdownDescription: "VPN list ID",
+ Computed: true,
+ },
+ "vpn_list_version": schema.Int64Attribute{
+ MarkdownDescription: "VPN list version",
+ Computed: true,
+ },
+ "prefix_list_id": schema.StringAttribute{
+ MarkdownDescription: "Prefix list ID",
+ Computed: true,
+ },
+ "prefix_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Prefix list version",
+ Computed: true,
+ },
+ "vpn_id": schema.Int64Attribute{
+ MarkdownDescription: "VPN ID",
+ Computed: true,
+ },
+ "tloc_ip": schema.StringAttribute{
+ MarkdownDescription: "TLOC IP address",
+ Computed: true,
+ },
+ "tloc_color": schema.StringAttribute{
+ MarkdownDescription: "TLOC color",
+ Computed: true,
+ },
+ "tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: "TLOC encapsulation",
+ Computed: true,
+ },
+ "site_id": schema.Int64Attribute{
+ MarkdownDescription: "Site ID",
+ Computed: true,
+ },
+ "carrier": schema.StringAttribute{
+ MarkdownDescription: "Carrier",
+ Computed: true,
+ },
+ "domain_id": schema.Int64Attribute{
+ MarkdownDescription: "Domain ID",
+ Computed: true,
+ },
+ "group_id": schema.Int64Attribute{
+ MarkdownDescription: "Group ID",
+ Computed: true,
+ },
+ },
+ },
+ },
+ "action_entries": schema.ListNestedAttribute{
+ MarkdownDescription: "List of action entries",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: "Type of action entry",
+ Computed: true,
+ },
+ "set_parameters": schema.ListNestedAttribute{
+ MarkdownDescription: "List of set parameters",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: "Type of action entry",
+ Computed: true,
+ },
+ "tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: "TLOC list ID",
+ Computed: true,
+ },
+ "tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: "TLOC list version",
+ Computed: true,
+ },
+ "tloc_ip": schema.StringAttribute{
+ MarkdownDescription: "TLOC IP address",
+ Computed: true,
+ },
+ "tloc_color": schema.StringAttribute{
+ MarkdownDescription: "TLOC color",
+ Computed: true,
+ },
+ "tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: "TLOC encapsulation",
+ Computed: true,
+ },
+ "tloc_action": schema.StringAttribute{
+ MarkdownDescription: "TLOC action",
+ Computed: true,
+ },
+ "preference": schema.Int64Attribute{
+ MarkdownDescription: "Preference",
+ Computed: true,
+ },
+ "omp_tag": schema.Int64Attribute{
+ MarkdownDescription: "OMP tag",
+ Computed: true,
+ },
+ "community": schema.StringAttribute{
+ MarkdownDescription: "Community value, e.g. `1000:10000` or `internet` or `local-AS`",
+ Computed: true,
+ },
+ "community_additive": schema.BoolAttribute{
+ MarkdownDescription: "Community additive",
+ Computed: true,
+ },
+ "service_type": schema.StringAttribute{
+ MarkdownDescription: "Service type",
+ Computed: true,
+ },
+ "service_vpn_id": schema.Int64Attribute{
+ MarkdownDescription: "Service VPN ID",
+ Computed: true,
+ },
+ "service_tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: "Service TLOC list ID",
+ Computed: true,
+ },
+ "service_tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Service TLOC list version",
+ Computed: true,
+ },
+ "service_tloc_ip": schema.StringAttribute{
+ MarkdownDescription: "Service TLOC IP address",
+ Computed: true,
+ },
+ "service_tloc_color": schema.StringAttribute{
+ MarkdownDescription: "Service TLOC color",
+ Computed: true,
+ },
+ "service_tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: "Service TLOC encapsulation",
+ Computed: true,
+ },
+ },
+ },
+ },
+ "export_to_vpn_list_id": schema.StringAttribute{
+ MarkdownDescription: "Export to VPN list ID",
+ Computed: true,
+ },
+ "export_to_vpn_list_version": schema.Int64Attribute{
+ MarkdownDescription: "Export to VPN list version",
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (d *CustomControlTopologyPolicyDefinitionDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ d.client = req.ProviderData.(*SdwanProviderData).Client
+}
+
+func (d *CustomControlTopologyPolicyDefinitionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var config CustomControlTopology
+
+ // Read config
+ diags := req.Config.Get(ctx, &config)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+
+ res, err := d.client.Get("/template/policy/definition/control/" + config.Id.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err))
+ return
+ }
+
+ config.fromBody(ctx, res)
+ config.updateVersions(ctx, config)
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString()))
+
+ diags = resp.State.Set(ctx, &config)
+ resp.Diagnostics.Append(diags...)
+}
diff --git a/internal/provider/data_source_sdwan_custom_control_topology_policy_definition_test.go b/internal/provider/data_source_sdwan_custom_control_topology_policy_definition_test.go
new file mode 100644
index 00000000..72b9575b
--- /dev/null
+++ b/internal/provider/data_source_sdwan_custom_control_topology_policy_definition_test.go
@@ -0,0 +1,80 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by "gen/generator.go"; DO NOT EDIT.
+
+package provider
+
+import (
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccDataSourceSdwanCustomControlTopologyPolicyDefinition(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceSdwanCustomControlTopologyPolicyDefinitionConfig,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "default_action", "reject"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.id", "1"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.name", "Region1"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.type", "route"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.ip_type", "ipv4"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.match_entries.0.type", "ompTag"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.match_entries.0.omp_tag", "100"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.type", "set"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.set_parameters.0.type", "preference"),
+ resource.TestCheckResourceAttr("data.sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.set_parameters.0.preference", "100"),
+ ),
+ },
+ },
+ })
+}
+
+const testAccDataSourceSdwanCustomControlTopologyPolicyDefinitionConfig = `
+
+resource "sdwan_custom_control_topology_policy_definition" "test" {
+ name = "TF_TEST_MIN"
+ description = "Terraform integration test"
+ default_action = "reject"
+ sequences = [{
+ id = 1
+ name = "Region1"
+ type = "route"
+ ip_type = "ipv4"
+ match_entries = [{
+ type = "ompTag"
+ omp_tag = 100
+ }]
+ action_entries = [{
+ type = "set"
+ set_parameters = [{
+ type = "preference"
+ preference = 100
+ }]
+ }]
+ }]
+}
+
+data "sdwan_custom_control_topology_policy_definition" "test" {
+ id = sdwan_custom_control_topology_policy_definition.test.id
+}
+`
diff --git a/internal/provider/model_sdwan_custom_control_topology_policy_definition.go b/internal/provider/model_sdwan_custom_control_topology_policy_definition.go
new file mode 100644
index 00000000..aa647159
--- /dev/null
+++ b/internal/provider/model_sdwan_custom_control_topology_policy_definition.go
@@ -0,0 +1,886 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by "gen/generator.go"; DO NOT EDIT.
+
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/tidwall/gjson"
+ "github.com/tidwall/sjson"
+)
+
+type CustomControlTopology struct {
+ Id types.String `tfsdk:"id"`
+ Version types.Int64 `tfsdk:"version"`
+ Type types.String `tfsdk:"type"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ DefaultAction types.String `tfsdk:"default_action"`
+ Sequences []CustomControlTopologySequences `tfsdk:"sequences"`
+}
+
+type CustomControlTopologySequences struct {
+ Id types.Int64 `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Type types.String `tfsdk:"type"`
+ IpType types.String `tfsdk:"ip_type"`
+ MatchEntries []CustomControlTopologySequencesMatchEntries `tfsdk:"match_entries"`
+ ActionEntries []CustomControlTopologySequencesActionEntries `tfsdk:"action_entries"`
+}
+
+type CustomControlTopologySequencesMatchEntries struct {
+ Type types.String `tfsdk:"type"`
+ ColorListId types.String `tfsdk:"color_list_id"`
+ ColorListVersion types.Int64 `tfsdk:"color_list_version"`
+ CommunityListId types.String `tfsdk:"community_list_id"`
+ CommunityListVersion types.Int64 `tfsdk:"community_list_version"`
+ ExpandedCommunityListId types.String `tfsdk:"expanded_community_list_id"`
+ ExpandedCommunityListVersion types.Int64 `tfsdk:"expanded_community_list_version"`
+ OmpTag types.Int64 `tfsdk:"omp_tag"`
+ Origin types.String `tfsdk:"origin"`
+ Originator types.String `tfsdk:"originator"`
+ Preference types.Int64 `tfsdk:"preference"`
+ SiteListId types.String `tfsdk:"site_list_id"`
+ SiteListVersion types.Int64 `tfsdk:"site_list_version"`
+ PathType types.String `tfsdk:"path_type"`
+ TlocListId types.String `tfsdk:"tloc_list_id"`
+ TlocListVersion types.Int64 `tfsdk:"tloc_list_version"`
+ VpnListId types.String `tfsdk:"vpn_list_id"`
+ VpnListVersion types.Int64 `tfsdk:"vpn_list_version"`
+ PrefixListId types.String `tfsdk:"prefix_list_id"`
+ PrefixListVersion types.Int64 `tfsdk:"prefix_list_version"`
+ VpnId types.Int64 `tfsdk:"vpn_id"`
+ TlocIp types.String `tfsdk:"tloc_ip"`
+ TlocColor types.String `tfsdk:"tloc_color"`
+ TlocEncapsulation types.String `tfsdk:"tloc_encapsulation"`
+ SiteId types.Int64 `tfsdk:"site_id"`
+ Carrier types.String `tfsdk:"carrier"`
+ DomainId types.Int64 `tfsdk:"domain_id"`
+ GroupId types.Int64 `tfsdk:"group_id"`
+}
+type CustomControlTopologySequencesActionEntries struct {
+ Type types.String `tfsdk:"type"`
+ SetParameters []CustomControlTopologySequencesActionEntriesSetParameters `tfsdk:"set_parameters"`
+ ExportToVpnListId types.String `tfsdk:"export_to_vpn_list_id"`
+ ExportToVpnListVersion types.Int64 `tfsdk:"export_to_vpn_list_version"`
+}
+
+type CustomControlTopologySequencesActionEntriesSetParameters struct {
+ Type types.String `tfsdk:"type"`
+ TlocListId types.String `tfsdk:"tloc_list_id"`
+ TlocListVersion types.Int64 `tfsdk:"tloc_list_version"`
+ TlocIp types.String `tfsdk:"tloc_ip"`
+ TlocColor types.String `tfsdk:"tloc_color"`
+ TlocEncapsulation types.String `tfsdk:"tloc_encapsulation"`
+ TlocAction types.String `tfsdk:"tloc_action"`
+ Preference types.Int64 `tfsdk:"preference"`
+ OmpTag types.Int64 `tfsdk:"omp_tag"`
+ Community types.String `tfsdk:"community"`
+ CommunityAdditive types.Bool `tfsdk:"community_additive"`
+ ServiceType types.String `tfsdk:"service_type"`
+ ServiceVpnId types.Int64 `tfsdk:"service_vpn_id"`
+ ServiceTlocListId types.String `tfsdk:"service_tloc_list_id"`
+ ServiceTlocListVersion types.Int64 `tfsdk:"service_tloc_list_version"`
+ ServiceTlocIp types.String `tfsdk:"service_tloc_ip"`
+ ServiceTlocColor types.String `tfsdk:"service_tloc_color"`
+ ServiceTlocEncapsulation types.String `tfsdk:"service_tloc_encapsulation"`
+}
+
+func (data CustomControlTopology) getType() string {
+ return "control"
+}
+
+func (data CustomControlTopology) toBody(ctx context.Context) string {
+ body, _ := sjson.Set("", "name", data.Name.ValueString())
+ body, _ = sjson.Set(body, "description", data.Description.ValueString())
+ body, _ = sjson.Set(body, "type", "control")
+ path := ""
+ if !data.DefaultAction.IsNull() {
+ body, _ = sjson.Set(body, path+"defaultAction.type", data.DefaultAction.ValueString())
+ }
+ if len(data.Sequences) > 0 {
+ body, _ = sjson.Set(body, path+"sequences", []interface{}{})
+ for _, item := range data.Sequences {
+ itemBody := ""
+ if !item.Id.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "sequenceId", item.Id.ValueInt64())
+ }
+ if !item.Name.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "sequenceName", item.Name.ValueString())
+ }
+ if !item.Type.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "sequenceType", item.Type.ValueString())
+ }
+ if !item.IpType.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "sequenceIpType", item.IpType.ValueString())
+ }
+ if len(item.MatchEntries) > 0 {
+ itemBody, _ = sjson.Set(itemBody, "match.entries", []interface{}{})
+ for _, childItem := range item.MatchEntries {
+ itemChildBody := ""
+ if !childItem.Type.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "field", childItem.Type.ValueString())
+ }
+ if !childItem.ColorListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.ColorListId.ValueString())
+ }
+ if !childItem.CommunityListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.CommunityListId.ValueString())
+ }
+ if !childItem.ExpandedCommunityListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.ExpandedCommunityListId.ValueString())
+ }
+ if !childItem.OmpTag.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.OmpTag.ValueInt64()))
+ }
+ if !childItem.Origin.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.Origin.ValueString())
+ }
+ if !childItem.Originator.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.Originator.ValueString())
+ }
+ if !childItem.Preference.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.Preference.ValueInt64()))
+ }
+ if !childItem.SiteListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.SiteListId.ValueString())
+ }
+ if !childItem.PathType.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.PathType.ValueString())
+ }
+ if !childItem.TlocListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.TlocListId.ValueString())
+ }
+ if !childItem.VpnListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.VpnListId.ValueString())
+ }
+ if !childItem.PrefixListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.PrefixListId.ValueString())
+ }
+ if !childItem.VpnId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.VpnId.ValueInt64()))
+ }
+ if !childItem.TlocIp.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value.ip", childItem.TlocIp.ValueString())
+ }
+ if !childItem.TlocColor.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value.color", childItem.TlocColor.ValueString())
+ }
+ if !childItem.TlocEncapsulation.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value.encap", childItem.TlocEncapsulation.ValueString())
+ }
+ if !childItem.SiteId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.SiteId.ValueInt64()))
+ }
+ if !childItem.Carrier.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.Carrier.ValueString())
+ }
+ if !childItem.DomainId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.DomainId.ValueInt64()))
+ }
+ if !childItem.GroupId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.GroupId.ValueInt64()))
+ }
+ itemBody, _ = sjson.SetRaw(itemBody, "match.entries.-1", itemChildBody)
+ }
+ }
+ if len(item.ActionEntries) > 0 {
+ itemBody, _ = sjson.Set(itemBody, "actions", []interface{}{})
+ for _, childItem := range item.ActionEntries {
+ itemChildBody := ""
+ if !childItem.Type.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "type", childItem.Type.ValueString())
+ }
+ if len(childItem.SetParameters) > 0 {
+ itemChildBody, _ = sjson.Set(itemChildBody, "parameter", []interface{}{})
+ for _, childChildItem := range childItem.SetParameters {
+ itemChildChildBody := ""
+ if !childChildItem.Type.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "field", childChildItem.Type.ValueString())
+ }
+ if !childChildItem.TlocListId.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "ref", childChildItem.TlocListId.ValueString())
+ }
+ if !childChildItem.TlocIp.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.ip", childChildItem.TlocIp.ValueString())
+ }
+ if !childChildItem.TlocColor.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.color", childChildItem.TlocColor.ValueString())
+ }
+ if !childChildItem.TlocEncapsulation.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.encap", childChildItem.TlocEncapsulation.ValueString())
+ }
+ if !childChildItem.TlocAction.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value", childChildItem.TlocAction.ValueString())
+ }
+ if !childChildItem.Preference.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value", fmt.Sprint(childChildItem.Preference.ValueInt64()))
+ }
+ if !childChildItem.OmpTag.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value", fmt.Sprint(childChildItem.OmpTag.ValueInt64()))
+ }
+ if !childChildItem.Community.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value", childChildItem.Community.ValueString())
+ }
+ if !childChildItem.ServiceType.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.type", childChildItem.ServiceType.ValueString())
+ }
+ if !childChildItem.ServiceVpnId.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.vpn", fmt.Sprint(childChildItem.ServiceVpnId.ValueInt64()))
+ }
+ if !childChildItem.ServiceTlocListId.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.tlocList", childChildItem.ServiceTlocListId.ValueString())
+ }
+ if !childChildItem.ServiceTlocIp.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.tloc.ip", childChildItem.ServiceTlocIp.ValueString())
+ }
+ if !childChildItem.ServiceTlocColor.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.tloc.color", childChildItem.ServiceTlocColor.ValueString())
+ }
+ if !childChildItem.ServiceTlocEncapsulation.IsNull() {
+ itemChildChildBody, _ = sjson.Set(itemChildChildBody, "value.tloc.encap", childChildItem.ServiceTlocEncapsulation.ValueString())
+ }
+ itemChildBody, _ = sjson.SetRaw(itemChildBody, "parameter.-1", itemChildChildBody)
+ }
+ }
+ if !childItem.ExportToVpnListId.IsNull() {
+ itemChildBody, _ = sjson.Set(itemChildBody, "parameter.ref", childItem.ExportToVpnListId.ValueString())
+ }
+ itemBody, _ = sjson.SetRaw(itemBody, "actions.-1", itemChildBody)
+ }
+ }
+ body, _ = sjson.SetRaw(body, path+"sequences.-1", itemBody)
+ }
+ }
+ return body
+}
+
+func (data *CustomControlTopology) fromBody(ctx context.Context, res gjson.Result) {
+ if value := res.Get("name"); value.Exists() {
+ data.Name = types.StringValue(value.String())
+ } else {
+ data.Name = types.StringNull()
+ }
+ if value := res.Get("description"); value.Exists() {
+ data.Description = types.StringValue(value.String())
+ } else {
+ data.Description = types.StringNull()
+ }
+ if value := res.Get("type"); value.Exists() {
+ data.Type = types.StringValue(value.String())
+ } else {
+ data.Type = types.StringNull()
+ }
+ path := ""
+ if value := res.Get(path + "defaultAction.type"); value.Exists() {
+ data.DefaultAction = types.StringValue(value.String())
+ } else {
+ data.DefaultAction = types.StringNull()
+ }
+ if value := res.Get(path + "sequences"); value.Exists() {
+ data.Sequences = make([]CustomControlTopologySequences, 0)
+ value.ForEach(func(k, v gjson.Result) bool {
+ item := CustomControlTopologySequences{}
+ if cValue := v.Get("sequenceId"); cValue.Exists() {
+ item.Id = types.Int64Value(cValue.Int())
+ } else {
+ item.Id = types.Int64Null()
+ }
+ if cValue := v.Get("sequenceName"); cValue.Exists() {
+ item.Name = types.StringValue(cValue.String())
+ } else {
+ item.Name = types.StringNull()
+ }
+ if cValue := v.Get("sequenceType"); cValue.Exists() {
+ item.Type = types.StringValue(cValue.String())
+ } else {
+ item.Type = types.StringNull()
+ }
+ if cValue := v.Get("sequenceIpType"); cValue.Exists() {
+ item.IpType = types.StringValue(cValue.String())
+ } else {
+ item.IpType = types.StringNull()
+ }
+ if cValue := v.Get("match.entries"); cValue.Exists() {
+ item.MatchEntries = make([]CustomControlTopologySequencesMatchEntries, 0)
+ cValue.ForEach(func(ck, cv gjson.Result) bool {
+ cItem := CustomControlTopologySequencesMatchEntries{}
+ if ccValue := cv.Get("field"); ccValue.Exists() {
+ cItem.Type = types.StringValue(ccValue.String())
+ } else {
+ cItem.Type = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "colorList" && ccValue.Exists() {
+ cItem.ColorListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.ColorListId = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "community" && ccValue.Exists() {
+ cItem.CommunityListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.CommunityListId = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "expandedCommunity" && ccValue.Exists() {
+ cItem.ExpandedCommunityListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.ExpandedCommunityListId = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "ompTag" && ccValue.Exists() {
+ cItem.OmpTag = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.OmpTag = types.Int64Null()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "origin" && ccValue.Exists() {
+ cItem.Origin = types.StringValue(ccValue.String())
+ } else {
+ cItem.Origin = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "originator" && ccValue.Exists() {
+ cItem.Originator = types.StringValue(ccValue.String())
+ } else {
+ cItem.Originator = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "preference" && ccValue.Exists() {
+ cItem.Preference = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.Preference = types.Int64Null()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "siteList" && ccValue.Exists() {
+ cItem.SiteListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.SiteListId = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "pathType" && ccValue.Exists() {
+ cItem.PathType = types.StringValue(ccValue.String())
+ } else {
+ cItem.PathType = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "tlocList" && ccValue.Exists() {
+ cItem.TlocListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.TlocListId = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "vpnList" && ccValue.Exists() {
+ cItem.VpnListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.VpnListId = types.StringNull()
+ }
+ if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "prefixList" && ccValue.Exists() {
+ cItem.PrefixListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.PrefixListId = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "vpn" && ccValue.Exists() {
+ cItem.VpnId = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.VpnId = types.Int64Null()
+ }
+ if ccValue := cv.Get("value.ip"); cItem.Type.ValueString() == "tloc" && ccValue.Exists() {
+ cItem.TlocIp = types.StringValue(ccValue.String())
+ } else {
+ cItem.TlocIp = types.StringNull()
+ }
+ if ccValue := cv.Get("value.color"); cItem.Type.ValueString() == "tloc" && ccValue.Exists() {
+ cItem.TlocColor = types.StringValue(ccValue.String())
+ } else {
+ cItem.TlocColor = types.StringNull()
+ }
+ if ccValue := cv.Get("value.encap"); cItem.Type.ValueString() == "tloc" && ccValue.Exists() {
+ cItem.TlocEncapsulation = types.StringValue(ccValue.String())
+ } else {
+ cItem.TlocEncapsulation = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "siteId" && ccValue.Exists() {
+ cItem.SiteId = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.SiteId = types.Int64Null()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "carrier" && ccValue.Exists() {
+ cItem.Carrier = types.StringValue(ccValue.String())
+ } else {
+ cItem.Carrier = types.StringNull()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "domainId" && ccValue.Exists() {
+ cItem.DomainId = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.DomainId = types.Int64Null()
+ }
+ if ccValue := cv.Get("value"); cItem.Type.ValueString() == "groupId" && ccValue.Exists() {
+ cItem.GroupId = types.Int64Value(ccValue.Int())
+ } else {
+ cItem.GroupId = types.Int64Null()
+ }
+ item.MatchEntries = append(item.MatchEntries, cItem)
+ return true
+ })
+ }
+ if cValue := v.Get("actions"); cValue.Exists() {
+ item.ActionEntries = make([]CustomControlTopologySequencesActionEntries, 0)
+ cValue.ForEach(func(ck, cv gjson.Result) bool {
+ cItem := CustomControlTopologySequencesActionEntries{}
+ if ccValue := cv.Get("type"); ccValue.Exists() {
+ cItem.Type = types.StringValue(ccValue.String())
+ } else {
+ cItem.Type = types.StringNull()
+ }
+ if ccValue := cv.Get("parameter"); ccValue.Exists() {
+ cItem.SetParameters = make([]CustomControlTopologySequencesActionEntriesSetParameters, 0)
+ ccValue.ForEach(func(cck, ccv gjson.Result) bool {
+ ccItem := CustomControlTopologySequencesActionEntriesSetParameters{}
+ if cccValue := ccv.Get("field"); cccValue.Exists() {
+ ccItem.Type = types.StringValue(cccValue.String())
+ } else {
+ ccItem.Type = types.StringNull()
+ }
+ if cccValue := ccv.Get("ref"); ccItem.Type.ValueString() == "tlocList" && cccValue.Exists() {
+ ccItem.TlocListId = types.StringValue(cccValue.String())
+ } else {
+ ccItem.TlocListId = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.ip"); ccItem.Type.ValueString() == "tloc" && cccValue.Exists() {
+ ccItem.TlocIp = types.StringValue(cccValue.String())
+ } else {
+ ccItem.TlocIp = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.color"); ccItem.Type.ValueString() == "tloc" && cccValue.Exists() {
+ ccItem.TlocColor = types.StringValue(cccValue.String())
+ } else {
+ ccItem.TlocColor = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.encap"); ccItem.Type.ValueString() == "tloc" && cccValue.Exists() {
+ ccItem.TlocEncapsulation = types.StringValue(cccValue.String())
+ } else {
+ ccItem.TlocEncapsulation = types.StringNull()
+ }
+ if cccValue := ccv.Get("value"); ccItem.Type.ValueString() == "tlocAction" && cccValue.Exists() {
+ ccItem.TlocAction = types.StringValue(cccValue.String())
+ } else {
+ ccItem.TlocAction = types.StringNull()
+ }
+ if cccValue := ccv.Get("value"); ccItem.Type.ValueString() == "preference" && cccValue.Exists() {
+ ccItem.Preference = types.Int64Value(cccValue.Int())
+ } else {
+ ccItem.Preference = types.Int64Null()
+ }
+ if cccValue := ccv.Get("value"); ccItem.Type.ValueString() == "ompTag" && cccValue.Exists() {
+ ccItem.OmpTag = types.Int64Value(cccValue.Int())
+ } else {
+ ccItem.OmpTag = types.Int64Null()
+ }
+ if cccValue := ccv.Get("value"); ccItem.Type.ValueString() == "community" && cccValue.Exists() {
+ ccItem.Community = types.StringValue(cccValue.String())
+ } else {
+ ccItem.Community = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.type"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceType = types.StringValue(cccValue.String())
+ } else {
+ ccItem.ServiceType = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.vpn"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceVpnId = types.Int64Value(cccValue.Int())
+ } else {
+ ccItem.ServiceVpnId = types.Int64Null()
+ }
+ if cccValue := ccv.Get("value.tlocList"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceTlocListId = types.StringValue(cccValue.String())
+ } else {
+ ccItem.ServiceTlocListId = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.tloc.ip"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceTlocIp = types.StringValue(cccValue.String())
+ } else {
+ ccItem.ServiceTlocIp = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.tloc.color"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceTlocColor = types.StringValue(cccValue.String())
+ } else {
+ ccItem.ServiceTlocColor = types.StringNull()
+ }
+ if cccValue := ccv.Get("value.tloc.encap"); ccItem.Type.ValueString() == "service" && cccValue.Exists() {
+ ccItem.ServiceTlocEncapsulation = types.StringValue(cccValue.String())
+ } else {
+ ccItem.ServiceTlocEncapsulation = types.StringNull()
+ }
+ cItem.SetParameters = append(cItem.SetParameters, ccItem)
+ return true
+ })
+ }
+ if ccValue := cv.Get("parameter.ref"); ccValue.Exists() {
+ cItem.ExportToVpnListId = types.StringValue(ccValue.String())
+ } else {
+ cItem.ExportToVpnListId = types.StringNull()
+ }
+ item.ActionEntries = append(item.ActionEntries, cItem)
+ return true
+ })
+ }
+ data.Sequences = append(data.Sequences, item)
+ return true
+ })
+ }
+}
+
+func (data *CustomControlTopology) hasChanges(ctx context.Context, state *CustomControlTopology) bool {
+ hasChanges := false
+ if !data.Name.Equal(state.Name) {
+ hasChanges = true
+ }
+ if !data.Description.Equal(state.Description) {
+ hasChanges = true
+ }
+ if !data.DefaultAction.Equal(state.DefaultAction) {
+ hasChanges = true
+ }
+ if len(data.Sequences) != len(state.Sequences) {
+ hasChanges = true
+ } else {
+ for i := range data.Sequences {
+ if !data.Sequences[i].Id.Equal(state.Sequences[i].Id) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].Name.Equal(state.Sequences[i].Name) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].Type.Equal(state.Sequences[i].Type) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].IpType.Equal(state.Sequences[i].IpType) {
+ hasChanges = true
+ }
+ if len(data.Sequences[i].MatchEntries) != len(state.Sequences[i].MatchEntries) {
+ hasChanges = true
+ } else {
+ for ii := range data.Sequences[i].MatchEntries {
+ if !data.Sequences[i].MatchEntries[ii].Type.Equal(state.Sequences[i].MatchEntries[ii].Type) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].ColorListId.Equal(state.Sequences[i].MatchEntries[ii].ColorListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].CommunityListId.Equal(state.Sequences[i].MatchEntries[ii].CommunityListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].ExpandedCommunityListId.Equal(state.Sequences[i].MatchEntries[ii].ExpandedCommunityListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].OmpTag.Equal(state.Sequences[i].MatchEntries[ii].OmpTag) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].Origin.Equal(state.Sequences[i].MatchEntries[ii].Origin) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].Originator.Equal(state.Sequences[i].MatchEntries[ii].Originator) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].Preference.Equal(state.Sequences[i].MatchEntries[ii].Preference) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].SiteListId.Equal(state.Sequences[i].MatchEntries[ii].SiteListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].PathType.Equal(state.Sequences[i].MatchEntries[ii].PathType) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].TlocListId.Equal(state.Sequences[i].MatchEntries[ii].TlocListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].VpnListId.Equal(state.Sequences[i].MatchEntries[ii].VpnListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].PrefixListId.Equal(state.Sequences[i].MatchEntries[ii].PrefixListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].VpnId.Equal(state.Sequences[i].MatchEntries[ii].VpnId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].TlocIp.Equal(state.Sequences[i].MatchEntries[ii].TlocIp) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].TlocColor.Equal(state.Sequences[i].MatchEntries[ii].TlocColor) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].TlocEncapsulation.Equal(state.Sequences[i].MatchEntries[ii].TlocEncapsulation) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].SiteId.Equal(state.Sequences[i].MatchEntries[ii].SiteId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].Carrier.Equal(state.Sequences[i].MatchEntries[ii].Carrier) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].DomainId.Equal(state.Sequences[i].MatchEntries[ii].DomainId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].MatchEntries[ii].GroupId.Equal(state.Sequences[i].MatchEntries[ii].GroupId) {
+ hasChanges = true
+ }
+ }
+ }
+ if len(data.Sequences[i].ActionEntries) != len(state.Sequences[i].ActionEntries) {
+ hasChanges = true
+ } else {
+ for ii := range data.Sequences[i].ActionEntries {
+ if !data.Sequences[i].ActionEntries[ii].Type.Equal(state.Sequences[i].ActionEntries[ii].Type) {
+ hasChanges = true
+ }
+ if len(data.Sequences[i].ActionEntries[ii].SetParameters) != len(state.Sequences[i].ActionEntries[ii].SetParameters) {
+ hasChanges = true
+ } else {
+ for iii := range data.Sequences[i].ActionEntries[ii].SetParameters {
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].Type.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].Type) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocListId.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocIp.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocIp) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocColor.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocColor) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocEncapsulation.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocEncapsulation) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocAction.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].TlocAction) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].Preference.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].Preference) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].OmpTag.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].OmpTag) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].Community.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].Community) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].CommunityAdditive.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].CommunityAdditive) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceType.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceType) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceVpnId.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceVpnId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocListId.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocListId) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocIp.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocIp) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocColor.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocColor) {
+ hasChanges = true
+ }
+ if !data.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocEncapsulation.Equal(state.Sequences[i].ActionEntries[ii].SetParameters[iii].ServiceTlocEncapsulation) {
+ hasChanges = true
+ }
+ }
+ }
+ if !data.Sequences[i].ActionEntries[ii].ExportToVpnListId.Equal(state.Sequences[i].ActionEntries[ii].ExportToVpnListId) {
+ hasChanges = true
+ }
+ }
+ }
+ }
+ }
+ return hasChanges
+}
+
+func (data *CustomControlTopology) getMatchColorListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "colorList" {
+ return cItem.ColorListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchCommunityListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "community" {
+ return cItem.CommunityListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchExpandedCommunityListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "expandedCommunity" {
+ return cItem.ExpandedCommunityListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchSiteListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "siteList" {
+ return cItem.SiteListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchTlocListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "tlocList" {
+ return cItem.TlocListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchVpnListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "vpnList" {
+ return cItem.VpnListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getMatchPrefixListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.MatchEntries {
+ if cItem.Type.ValueString() == "prefixList" {
+ return cItem.PrefixListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getActionExportToVpnListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.ActionEntries {
+ if cItem.Type.ValueString() == "exportTo" {
+ return cItem.ExportToVpnListVersion
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getActionTlocListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.ActionEntries {
+ if cItem.Type.ValueString() == "set" {
+ for _, ccItem := range cItem.SetParameters {
+ if ccItem.Type.ValueString() == "tlocList" {
+ return ccItem.TlocListVersion
+ }
+ }
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) getActionServiceTlocListVersion(ctx context.Context, name string, id int64) types.Int64 {
+ for _, item := range data.Sequences {
+ if item.Name.ValueString() == name && item.Id.ValueInt64() == id {
+ for _, cItem := range item.ActionEntries {
+ if cItem.Type.ValueString() == "set" {
+ for _, ccItem := range cItem.SetParameters {
+ if ccItem.Type.ValueString() == "service" {
+ return ccItem.ServiceTlocListVersion
+ }
+ }
+ }
+ }
+ }
+ }
+ return types.Int64Null()
+}
+
+func (data *CustomControlTopology) updateVersions(ctx context.Context, state CustomControlTopology) {
+ for s := range data.Sequences {
+ id := data.Sequences[s].Id.ValueInt64()
+ name := data.Sequences[s].Name.ValueString()
+ for m := range data.Sequences[s].MatchEntries {
+ t := data.Sequences[s].MatchEntries[m].Type.ValueString()
+ if t == "colorList" {
+ data.Sequences[s].MatchEntries[m].ColorListVersion = state.getMatchColorListVersion(ctx, name, id)
+ } else if t == "community" {
+ data.Sequences[s].MatchEntries[m].CommunityListVersion = state.getMatchCommunityListVersion(ctx, name, id)
+ } else if t == "expandedCommunity" {
+ data.Sequences[s].MatchEntries[m].ExpandedCommunityListVersion = state.getMatchExpandedCommunityListVersion(ctx, name, id)
+ } else if t == "siteList" {
+ data.Sequences[s].MatchEntries[m].SiteListVersion = state.getMatchSiteListVersion(ctx, name, id)
+ } else if t == "tlocList" {
+ data.Sequences[s].MatchEntries[m].TlocListVersion = state.getMatchTlocListVersion(ctx, name, id)
+ } else if t == "vpnList" {
+ data.Sequences[s].MatchEntries[m].VpnListVersion = state.getMatchVpnListVersion(ctx, name, id)
+ } else if t == "prefixList" {
+ data.Sequences[s].MatchEntries[m].PrefixListVersion = state.getMatchPrefixListVersion(ctx, name, id)
+ }
+ }
+ for a := range data.Sequences[s].ActionEntries {
+ t := data.Sequences[s].ActionEntries[a].Type.ValueString()
+ if t == "set" {
+ for s := range data.Sequences[s].ActionEntries[a].SetParameters {
+ st := data.Sequences[s].ActionEntries[a].SetParameters[s].Type.ValueString()
+ if st == "tlocList" {
+ data.Sequences[s].ActionEntries[a].SetParameters[s].TlocListVersion = state.getActionTlocListVersion(ctx, name, id)
+ } else if st == "service" && data.Sequences[s].ActionEntries[a].SetParameters[s].ServiceTlocListId.ValueString() != "" {
+ data.Sequences[s].ActionEntries[a].SetParameters[s].ServiceTlocListVersion = state.getActionServiceTlocListVersion(ctx, name, id)
+ }
+ }
+ } else if t == "exportTo" {
+ data.Sequences[s].ActionEntries[a].ExportToVpnListVersion = state.getActionExportToVpnListVersion(ctx, name, id)
+ }
+ }
+ }
+}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index e59c3d04..be5d037c 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -282,6 +282,7 @@ func (p *SdwanProvider) Resources(ctx context.Context) []func() resource.Resourc
NewTLOCListPolicyObjectResource,
NewVPNListPolicyObjectResource,
NewACLPolicyDefinitionResource,
+ NewCustomControlTopologyPolicyDefinitionResource,
NewDeviceACLPolicyDefinitionResource,
NewHubAndSpokeTopologyPolicyDefinitionResource,
NewMeshTopologyPolicyDefinitionResource,
@@ -338,6 +339,7 @@ func (p *SdwanProvider) DataSources(ctx context.Context) []func() datasource.Dat
NewTLOCListPolicyObjectDataSource,
NewVPNListPolicyObjectDataSource,
NewACLPolicyDefinitionDataSource,
+ NewCustomControlTopologyPolicyDefinitionDataSource,
NewDeviceACLPolicyDefinitionDataSource,
NewHubAndSpokeTopologyPolicyDefinitionDataSource,
NewMeshTopologyPolicyDefinitionDataSource,
diff --git a/internal/provider/resource_sdwan_custom_control_topology_policy_definition.go b/internal/provider/resource_sdwan_custom_control_topology_policy_definition.go
new file mode 100644
index 00000000..d9833bdc
--- /dev/null
+++ b/internal/provider/resource_sdwan_custom_control_topology_policy_definition.go
@@ -0,0 +1,555 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by "gen/generator.go"; DO NOT EDIT.
+
+package provider
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/CiscoDevNet/terraform-provider-sdwan/internal/provider/helpers"
+ "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/netascode/go-sdwan"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces
+var _ resource.Resource = &CustomControlTopologyPolicyDefinitionResource{}
+var _ resource.ResourceWithImportState = &CustomControlTopologyPolicyDefinitionResource{}
+
+func NewCustomControlTopologyPolicyDefinitionResource() resource.Resource {
+ return &CustomControlTopologyPolicyDefinitionResource{}
+}
+
+type CustomControlTopologyPolicyDefinitionResource struct {
+ client *sdwan.Client
+ updateMutex *sync.Mutex
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_custom_control_topology_policy_definition"
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ // This description is used by the documentation generator and the language server.
+ MarkdownDescription: helpers.NewAttributeDescription("This resource can manage a Custom Control Topology policy definition.").String,
+
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ MarkdownDescription: "The id of the policy definition",
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ "version": schema.Int64Attribute{
+ MarkdownDescription: "The version of the policy definition",
+ Computed: true,
+ },
+ "type": schema.StringAttribute{
+ MarkdownDescription: "The policy defintion type",
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ "name": schema.StringAttribute{
+ MarkdownDescription: "The name of the policy definition",
+ Required: true,
+ },
+ "description": schema.StringAttribute{
+ MarkdownDescription: "The description of the policy definition",
+ Required: true,
+ },
+ "default_action": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Default action, either `accept` or `reject`").AddStringEnumDescription("accept", "reject").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("accept", "reject"),
+ },
+ },
+ "sequences": schema.ListNestedAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("List of sequences").String,
+ Required: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Sequence ID").String,
+ Required: true,
+ },
+ "name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Sequence name").String,
+ Required: true,
+ },
+ "type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Sequence type, either `route` or `tloc`").AddStringEnumDescription("route", "tloc").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("route", "tloc"),
+ },
+ },
+ "ip_type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Sequence IP type, either `ipv4`, `ipv6` or `all`").AddStringEnumDescription("ipv4", "ipv6", "all").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("ipv4", "ipv6", "all"),
+ },
+ },
+ "match_entries": schema.ListNestedAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("List of match entries").String,
+ Optional: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Type of match entry").AddStringEnumDescription("colorList", "community", "expandedCommunity", "ompTag", "origin", "originator", "preference", "siteList", "pathType", "tlocList", "vpnList", "prefixList", "vpn", "tloc", "siteId", "carrier", "domainId", "groupId").String,
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("colorList", "community", "expandedCommunity", "ompTag", "origin", "originator", "preference", "siteList", "pathType", "tlocList", "vpnList", "prefixList", "vpn", "tloc", "siteId", "carrier", "domainId", "groupId"),
+ },
+ },
+ "color_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Color list ID").String,
+ Optional: true,
+ },
+ "color_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Color list version").String,
+ Optional: true,
+ },
+ "community_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Community list ID").String,
+ Optional: true,
+ },
+ "community_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Community list version").String,
+ Optional: true,
+ },
+ "expanded_community_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Expanded community list ID").String,
+ Optional: true,
+ },
+ "expanded_community_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Expanded community list version").String,
+ Optional: true,
+ },
+ "omp_tag": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("OMP tag").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "origin": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Origin").AddStringEnumDescription("igp", "egp", "incomplete").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("igp", "egp", "incomplete"),
+ },
+ },
+ "originator": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Originator IP").String,
+ Optional: true,
+ },
+ "preference": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Preference").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "site_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Site list ID").String,
+ Optional: true,
+ },
+ "site_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Site list version").String,
+ Optional: true,
+ },
+ "path_type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Path type").AddStringEnumDescription("hierarchical-path", "direct-path", "transport-gateway-path").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("hierarchical-path", "direct-path", "transport-gateway-path"),
+ },
+ },
+ "tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC list ID").String,
+ Optional: true,
+ },
+ "tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC list version").String,
+ Optional: true,
+ },
+ "vpn_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("VPN list ID").String,
+ Optional: true,
+ },
+ "vpn_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("VPN list version").String,
+ Optional: true,
+ },
+ "prefix_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Prefix list ID").String,
+ Optional: true,
+ },
+ "prefix_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Prefix list version").String,
+ Optional: true,
+ },
+ "vpn_id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("VPN ID").AddIntegerRangeDescription(0, 65536).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 65536),
+ },
+ },
+ "tloc_ip": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC IP address").String,
+ Optional: true,
+ },
+ "tloc_color": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC color").String,
+ Optional: true,
+ },
+ "tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC encapsulation").AddStringEnumDescription("ipsec", "gre").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("ipsec", "gre"),
+ },
+ },
+ "site_id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Site ID").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "carrier": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Carrier").AddStringEnumDescription("default", "carrier1", "carrier2", "carrier3", "carrier4", "carrier5", "carrier6", "carrier7", "carrier8").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("default", "carrier1", "carrier2", "carrier3", "carrier4", "carrier5", "carrier6", "carrier7", "carrier8"),
+ },
+ },
+ "domain_id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Domain ID").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "group_id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Group ID").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ },
+ },
+ },
+ "action_entries": schema.ListNestedAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("List of action entries").String,
+ Optional: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Type of action entry").AddStringEnumDescription("set", "exportTo").String,
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("set", "exportTo"),
+ },
+ },
+ "set_parameters": schema.ListNestedAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("List of set parameters").String,
+ Optional: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Type of action entry").AddStringEnumDescription("tlocList", "tloc", "tlocAction", "preference", "ompTag", "community", "communityAdditive", "service").String,
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("tlocList", "tloc", "tlocAction", "preference", "ompTag", "community", "communityAdditive", "service"),
+ },
+ },
+ "tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC list ID").String,
+ Optional: true,
+ },
+ "tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC list version").String,
+ Optional: true,
+ },
+ "tloc_ip": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC IP address").String,
+ Optional: true,
+ },
+ "tloc_color": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC color").String,
+ Optional: true,
+ },
+ "tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC encapsulation").AddStringEnumDescription("ipsec", "gre").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("ipsec", "gre"),
+ },
+ },
+ "tloc_action": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("TLOC action").AddStringEnumDescription("strict", "primary", "backup", "ecmp").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("strict", "primary", "backup", "ecmp"),
+ },
+ },
+ "preference": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Preference").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "omp_tag": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("OMP tag").AddIntegerRangeDescription(0, 4294967295).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 4294967295),
+ },
+ },
+ "community": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Community value, e.g. `1000:10000` or `internet` or `local-AS`").String,
+ Optional: true,
+ },
+ "community_additive": schema.BoolAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Community additive").String,
+ Optional: true,
+ },
+ "service_type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service type").AddStringEnumDescription("FW", "IDP", "IDS", "netsvc1", "netsvc2", "netsvc3", "netsvc4", "netsvc5").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("FW", "IDP", "IDS", "netsvc1", "netsvc2", "netsvc3", "netsvc4", "netsvc5"),
+ },
+ },
+ "service_vpn_id": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service VPN ID").AddIntegerRangeDescription(0, 65536).String,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.Between(0, 65536),
+ },
+ },
+ "service_tloc_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service TLOC list ID").String,
+ Optional: true,
+ },
+ "service_tloc_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service TLOC list version").String,
+ Optional: true,
+ },
+ "service_tloc_ip": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service TLOC IP address").String,
+ Optional: true,
+ },
+ "service_tloc_color": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service TLOC color").String,
+ Optional: true,
+ },
+ "service_tloc_encapsulation": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Service TLOC encapsulation").AddStringEnumDescription("ipsec", "gre").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("ipsec", "gre"),
+ },
+ },
+ },
+ },
+ },
+ "export_to_vpn_list_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Export to VPN list ID").String,
+ Optional: true,
+ },
+ "export_to_vpn_list_version": schema.Int64Attribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Export to VPN list version").String,
+ Optional: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ r.client = req.ProviderData.(*SdwanProviderData).Client
+ r.updateMutex = req.ProviderData.(*SdwanProviderData).UpdateMutex
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var plan CustomControlTopology
+
+ // Read plan
+ diags := req.Plan.Get(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Name.ValueString()))
+
+ // Create object
+ body := plan.toBody(ctx)
+
+ res, err := r.client.Post("/template/policy/definition/control", body)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST), got error: %s, %s", err, res.String()))
+ return
+ }
+
+ plan.Id = types.StringValue(res.Get("definitionId").String())
+ plan.Version = types.Int64Value(0)
+ plan.Type = types.StringValue(plan.getType())
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Name.ValueString()))
+
+ diags = resp.State.Set(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var state, oldState CustomControlTopology
+
+ // Read state
+ diags := req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ diags = req.State.Get(ctx, &oldState)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Name.String()))
+
+ res, err := r.client.Get("/template/policy/definition/control/" + state.Id.ValueString())
+ if res.Get("error.message").String() == "Failed to find specified resource" {
+ resp.State.RemoveResource(ctx)
+ return
+ } else if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+ return
+ }
+
+ state.fromBody(ctx, res)
+ state.updateVersions(ctx, oldState)
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Name.ValueString()))
+
+ diags = resp.State.Set(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var plan, state CustomControlTopology
+
+ // Read plan
+ diags := req.Plan.Get(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ // Read state
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Name.ValueString()))
+
+ if plan.hasChanges(ctx, &state) {
+ body := plan.toBody(ctx)
+ r.updateMutex.Lock()
+ res, err := r.client.Put("/template/policy/definition/control/"+plan.Id.ValueString(), body)
+ r.updateMutex.Unlock()
+ if err != nil {
+ if strings.Contains(res.Get("error.message").String(), "Failed to acquire lock") {
+ resp.Diagnostics.AddWarning("Client Warning", "Failed to modify policy due to policy being locked by another change. Policy changes will not be applied. Re-run 'terraform apply' to try again.")
+ } else {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
+ return
+ }
+ }
+ } else {
+ tflog.Debug(ctx, fmt.Sprintf("%s: No changes detected", plan.Name.ValueString()))
+ }
+
+ plan.Version = types.Int64Value(state.Version.ValueInt64() + 1)
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Name.ValueString()))
+
+ diags = resp.State.Set(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var state CustomControlTopology
+
+ // Read state
+ diags := req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Name.ValueString()))
+
+ res, err := r.client.Delete("/template/policy/definition/control/" + state.Id.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Name.ValueString()))
+
+ resp.State.RemoveResource(ctx)
+}
+
+func (r *CustomControlTopologyPolicyDefinitionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
diff --git a/internal/provider/resource_sdwan_custom_control_topology_policy_definition_test.go b/internal/provider/resource_sdwan_custom_control_topology_policy_definition_test.go
new file mode 100644
index 00000000..1a383f14
--- /dev/null
+++ b/internal/provider/resource_sdwan_custom_control_topology_policy_definition_test.go
@@ -0,0 +1,77 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+// Code generated by "gen/generator.go"; DO NOT EDIT.
+
+package provider
+
+import (
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccSdwanCustomControlTopologyPolicyDefinition(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccSdwanCustomControlTopologyPolicyDefinitionConfig_all(),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "default_action", "reject"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.id", "1"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.name", "Region1"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.type", "route"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.ip_type", "ipv4"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.match_entries.0.type", "ompTag"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.match_entries.0.omp_tag", "100"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.type", "set"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.set_parameters.0.type", "preference"),
+ resource.TestCheckResourceAttr("sdwan_custom_control_topology_policy_definition.test", "sequences.0.action_entries.0.set_parameters.0.preference", "100"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccSdwanCustomControlTopologyPolicyDefinitionConfig_all() string {
+ return `
+ resource "sdwan_custom_control_topology_policy_definition" "test" {
+ name = "TF_TEST_ALL"
+ description = "Terraform integration test"
+ default_action = "reject"
+ sequences = [{
+ id = 1
+ name = "Region1"
+ type = "route"
+ ip_type = "ipv4"
+ match_entries = [{
+ type = "ompTag"
+ omp_tag = 100
+ }]
+ action_entries = [{
+ type = "set"
+ set_parameters = [{
+ type = "preference"
+ preference = 100
+ }]
+ }]
+ }]
+ }
+ `
+}
diff --git a/templates/guides/changelog.md.tmpl b/templates/guides/changelog.md.tmpl
index 8f5fe6b8..8f43c441 100644
--- a/templates/guides/changelog.md.tmpl
+++ b/templates/guides/changelog.md.tmpl
@@ -14,6 +14,7 @@ description: |-
- Add `sdwan_cisco_secure_internet_gateway_feature_template` resource and data source
- Add `sdwan_hub_and_spoke_topology_policy_definition` resource and data source
- Add `sdwan_mesh_topology_policy_definition` resource and data source
+- Add `sdwan_custom_control_topology_policy_definition` resource and data source
## 0.2.0