diff --git a/docs/data-sources/bfd_template.md b/docs/data-sources/bfd_template.md new file mode 100644 index 00000000..70da72ae --- /dev/null +++ b/docs/data-sources/bfd_template.md @@ -0,0 +1,41 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_bfd_template Data Source - terraform-provider-fmc" +subcategory: "Objects" +description: |- + This data source can read the BFD Template. +--- + +# fmc_bfd_template (Data Source) + +This data source can read the BFD Template. + +## Example Usage + +```terraform +data "fmc_bfd_template" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Optional + +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object +- `name` (String) The name of the bfd template object. + +### Read-Only + +- `authentication_key_id` (Number) Authentication Key ID +- `authentication_password` (String) Password for BFD Authentication (1-24 characters) +- `authentication_type` (String) Authentication types +- `echo` (String) Enables/disables BFD echo. +- `hop_type` (String) The hop type. +- `interval_time` (String) Interval unit of measurement of time. +- `min_receive` (Number) BFD Minimum Receive unit value in ranges: 50-999 miliseconds, 50000-999000 microseconds +- `min_transmit` (Number) BFD Minimum Transmit unit value. +- `tx_rx_multiplier` (Number) BFD Multipler value. +- `type` (String) Type of the object; this value is always 'BFDTemplate'. diff --git a/docs/data-sources/device_bfd.md b/docs/data-sources/device_bfd.md new file mode 100644 index 00000000..e0644773 --- /dev/null +++ b/docs/data-sources/device_bfd.md @@ -0,0 +1,43 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bfd Data Source - terraform-provider-fmc" +subcategory: "Device" +description: |- + This data source can read the Device BFD. +--- + +# fmc_device_bfd (Data Source) + +This data source can read the Device BFD. + +## Example Usage + +```terraform +data "fmc_device_bfd" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent device (fmc_device.example.id). + +### Optional + +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object +- `interface_logical_name` (String) Logical Name of the interface of BFD assignment if SINGLE_HOP selected. + +### Read-Only + +- `bfd_template_id` (String) ID of the BFD Template +- `destination_host_object_id` (String) The ID of the destination host object if MULTI_HOP selected. +- `hop_type` (String) BFD Hop type. +- `interface_id` (String) ID of the interface of BFD assignment if SINGLE_HOP selected. +- `slow_timer` (Number) BFD Slow Timer value in range: 1000-30000, default: 1000 +- `source_host_object_id` (String) The ID of the source host object if MULTI_HOP selected. +- `type` (String) Type of the object; this value is always 'BFDPolicy' diff --git a/docs/data-sources/device_bgp.md b/docs/data-sources/device_bgp.md new file mode 100644 index 00000000..3affb45e --- /dev/null +++ b/docs/data-sources/device_bgp.md @@ -0,0 +1,193 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bgp Data Source - terraform-provider-fmc" +subcategory: "Devices" +description: |- + This data source can read the Device BGP. +--- + +# fmc_device_bgp (Data Source) + +This data source can read the Device BGP. + +## Example Usage + +```terraform +data "fmc_device_bgp" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent device (fmc_device.example.id). + +### Optional + +- `as_number` (String) Autonomus System (AS) Number +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object + +### Read-Only + +- `ipv4_address_family_type` (String) +- `ipv4_aggregate_addresses` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_aggregate_addresses)) +- `ipv4_auto_aummary` (Boolean) Summarize subnet routes into network level routes +- `ipv4_bgp_redistribute_internal` (Boolean) Redistribute IBGP into IGP. (Use filtering to limit the number of prefixes that are redistributed) +- `ipv4_bgp_supress_inactive` (Boolean) Suppresing advertise inactive routes +- `ipv4_default_information_orginate` (Boolean) Generate default routes +- `ipv4_external_distance` (Number) Administrative route distance for external routes +- `ipv4_filterings` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_filterings)) +- `ipv4_forward_packets_over_multipath_ebgp` (Number) Number of paths to use for EBGP +- `ipv4_forward_packets_over_multipath_ibgp` (Number) Number of paths to use for IBGP +- `ipv4_internal_distance` (Number) Administrative route distance for internal routes +- `ipv4_learned_route_map_id` (String) Learned Route Map ID +- `ipv4_local_distance` (Number) Administrative route distance for local routes +- `ipv4_neighbors` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors)) +- `ipv4_networks` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_networks)) +- `ipv4_redistributions` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_redistributions)) +- `ipv4_route_injections` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_route_injections)) +- `ipv4_synchronization` (Boolean) Synchronize between BGP and IGP systems +- `name` (String) Name of the object; this is always 'bgp' +- `type` (String) Type of the object; this is always 'bgp' + + +### Nested Schema for `ipv4_aggregate_addresses` + +Read-Only: + +- `advertise_map_id` (String) Advertise Map ID +- `attribute_map_id` (String) Attribute Map ID +- `filter` (Boolean) Filter all routes from updates (summary only) +- `generate_as` (Boolean) Generate AS set path information +- `network_id` (String) Network ID +- `suppress_map_id` (String) Suppress Map ID + + + +### Nested Schema for `ipv4_filterings` + +Read-Only: + +- `access_list_id` (String) Standard Access List ID +- `network_direction` (String) Filtering directrion +- `prorocol_process` (String) Process ID +- `protocol` (String) Protocol + + + +### Nested Schema for `ipv4_neighbors` + +Read-Only: + +- `enable_address_family` (Boolean) Enable IPv4 address family +- `neighbor_address` (String) IP address of the BGP neighbor +- `neighbor_authentication_password` (String) Setting password enables authentication. +- `neighbor_bfd` (String) BFD Fallover +- `neighbor_customized_accept_both_as` (Boolean) Accept either real AS number or local AS number in routes experienced from neighbor +- `neighbor_customized_local_as_number` (String) Customize the AS number for the routes received from neighbor +- `neighbor_customized_no_prepend` (Boolean) Do not prepend local AS number to routes received from neighbor +- `neighbor_customized_replace_as` (Boolean) Replace real AS number with local AS number in routes received from neighbor +- `neighbor_description` (String) Description of the neighbor +- `neighbor_disable_connection_verification` (Boolean) Disable Connection Verification +- `neighbor_filter_access_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_access_lists)) +- `neighbor_filter_as_path_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_as_path_lists)) +- `neighbor_filter_max_prefix` (Number) Maximum number of prefixes allowed from the neighbor +- `neighbor_filter_prefix_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_prefix_lists)) +- `neighbor_filter_restart_interval` (Number) Time interval to restart the maximum prefix limit in Minutes +- `neighbor_filter_route_map_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_route_map_lists)) +- `neighbor_filter_threshold_value` (Number) Threshold value for the maximum number of prefixes allowed from the neighbor +- `neighbor_filter_warning_only` (Boolean) Give only warning message when prefix limit exceeded or terminate peering when prefix limit is exceeded. +- `neighbor_generate_default_route_map_id` (String) Generate default routes - Route Map +- `neighbor_hold_time` (Number) Time interval to hold the neighbor in seconds +- `neighbor_keepalive_interval` (Number) Time interval to send keepalive messages in seconds +- `neighbor_max_hop_count` (Number) Maximum number of hops to reach the neighbor +- `neighbor_min_hold_time` (Number) Minimum hold time in seconds +- `neighbor_nexthop_self` (Boolean) Use itself as next hop for this neighbor +- `neighbor_remote_as` (String) AS number of the BGP neighbor +- `neighbor_routes_advertise_exist_nonexist_map_id` (String) Specified route maps are advertised when the prefix exists only in the Advertise Map. +- `neighbor_routes_advertise_map_id` (String) Specified route maps are advertised when the prefix exists in the Advertise Map and Exist Map. +- `neighbor_routes_advertise_map_use_exist` (Boolean) Use Exist Map or Non-Exist Map +- `neighbor_routes_advertisement_interval` (Number) Time interval to advertise routes in seconds +- `neighbor_routes_remove_private_as` (Boolean) Remove private AS numbers from outgoing routing updates +- `neighbor_send_community_attribute` (Boolean) Send Community attribute to this neighbor +- `neighbor_shutdown` (Boolean) Shutdown administratively +- `neighbor_tcp_mtu_path_discovery` (Boolean) Use TCP path MTU discovery. +- `neighbor_tcp_transport_mode` (Boolean) True set it to active, False to passive. +- `neighbor_version` (String) Set BPG version: 0 - default, 4 - IPv4 +- `neighbor_weight` (Number) Weight of the neighbor +- `update_source_interface_id` (String) Interface ID for the update source + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_access_lists` + +Read-Only: + +- `access_list_id` (String) Access List ID +- `update_direction` (String) Filter direction + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_as_path_lists` + +Read-Only: + +- `as_path_id` (String) AS Path ID +- `update_direction` (String) Filter direction + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_prefix_lists` + +Read-Only: + +- `prefix_list_id` (String) Route Map ID +- `update_direction` (String) Filter direction + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_route_map_lists` + +Read-Only: + +- `route_map_id` (String) Route Map ID +- `update_direction` (String) Filter direction + + + + +### Nested Schema for `ipv4_networks` + +Read-Only: + +- `network_id` (String) Network object ID +- `route_map_id` (String) Route Map ID + + + +### Nested Schema for `ipv4_redistributions` + +Read-Only: + +- `match_external1` (Boolean) Match OSPF External 1 metrics +- `match_external2` (Boolean) Match OSPF External 2 metrics +- `match_internal` (Boolean) Match OSPF Internal metrics +- `match_nssa_external1` (Boolean) Match OSPF NSSA External 1 metrics +- `match_nssa_external2` (Boolean) Match OSPF NSSA External 2 metrics +- `metric` (Number) Metric value +- `process_id` (String) process ID +- `route_map_id` (String) Route Map ID +- `source_protocol` (String) Protocol to redistribute + + + +### Nested Schema for `ipv4_route_injections` + +Read-Only: + +- `exist_route_map_id` (String) Exist Route Map ID +- `inject_route_map_id` (String) Inject Route Map ID diff --git a/docs/data-sources/device_bgp_general_settings.md b/docs/data-sources/device_bgp_general_settings.md new file mode 100644 index 00000000..d990a8b4 --- /dev/null +++ b/docs/data-sources/device_bgp_general_settings.md @@ -0,0 +1,59 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bgp_general_settings Data Source - terraform-provider-fmc" +subcategory: "Devices" +description: |- + This data source can read the Device BGP General Settings. +--- + +# fmc_device_bgp_general_settings (Data Source) + +This data source can read the Device BGP General Settings. + +## Example Usage + +```terraform +data "fmc_device_bgp_general_settings" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent device (fmc_device.example.id). + +### Optional + +- `as_number` (String) Autonomous System (AS) number in asplain or asdot format +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object + +### Read-Only + +- `aggregate_timer` (Number) Interval at which BGP routes will be aggregated or to disable timer-based router aggregation (in seconds). +- `as_number_in_path_attribute` (Number) Range to discard routes that have as-path segments that exceed a specified value. +- `compare_med_from_different_neighbors` (Boolean) Allow comparing MED from different neighbors +- `compare_router_id_in_path` (Boolean) Compare Router ID for identical EBGP paths +- `default_local_preference` (Number) Default local preference +- `enforce_first_peer_as` (Boolean) Discard updates received from an external BGP (eBGP) peers that do not list their autonomous system (AS) number. +- `graceful_restart` (Boolean) Enable graceful restart +- `graceful_restart_restart_time` (Number) Graceful Restart Time in seconds +- `graceful_restart_stale_path_time` (Number) Stalepath Time in seconds +- `hold_time` (Number) Hold time in seconds +- `keepalive_interval` (Number) Keepalive interval in seconds +- `log_neighbor_changes` (Boolean) Enable logging of BGP neighbor status changes. +- `min_hold_time` (Number) Minimum hold time (0 or 3-65535 seconds) +- `missing_med_as_best` (Boolean) Treat missing MED as the best preferred path +- `name` (String) Object name; Always set to 'AsaBGPGeneralTable' +- `next_hop_address_tracking` (Boolean) Enable next hop address tracking +- `next_hop_delay_interval` (Number) Next hop delay interval in seconds +- `pick_best_med` (Boolean) Pick the best-MED path among paths advertised by neighbor AS +- `reset_session_upon_failover` (Boolean) Reset session upon failover +- `router_id` (String) String value for the routerID. Possible values can be 'AUTOMATIC' or valid ipv4 address +- `scanning_interval` (Number) Scanning interval of BGP routers for next hop validation in Seconds. +- `tcp_path_mtu_discovery` (Boolean) Use TCP path MTU discovery. +- `use_dot_notation` (Boolean) Change format of BGP 4-byte autonomous system numbers from asplain (decimal values) to dot notation. diff --git a/docs/data-sources/device_ha_pair_monitoring.md b/docs/data-sources/device_ha_pair_monitoring.md new file mode 100644 index 00000000..618b03d2 --- /dev/null +++ b/docs/data-sources/device_ha_pair_monitoring.md @@ -0,0 +1,50 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_ha_pair_monitoring Data Source - terraform-provider-fmc" +subcategory: "Device" +description: |- + This data source can read the Device HA Pair Monitoring. +--- + +# fmc_device_ha_pair_monitoring (Data Source) + +This data source can read the Device HA Pair Monitoring. + +## Example Usage + +```terraform +data "fmc_device_ha_pair_monitoring" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent HA device (fmc_device.example.id). + +### Optional + +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object +- `logical_name` (String) Logical Name of the monitored interface. + +### Read-Only + +- `ipv4_active_address` (String) Active IPv4 address from the interface. +- `ipv4_netmask` (String) IPv4 Network Mask assigned on the interface. +- `ipv4_standby_address` (String) Standby IPv4 address. It has to be in the same subnet as primaty IP configured on this interface. +- `ipv6_addresses` (Attributes List) (see [below for nested schema](#nestedatt--ipv6_addresses)) +- `monitor_interface` (Boolean) Monitor this interface for failures. +- `type` (String) Type of the resource. + + +### Nested Schema for `ipv6_addresses` + +Read-Only: + +- `active_address` (String) Active IPv6 address with prefix. Address has to be configured on the interface. +- `standby_address` (String) Standby IPv6 address. Address has to be from the same subnet as active IPv6 address. diff --git a/docs/data-sources/device_subinterface.md b/docs/data-sources/device_subinterface.md index b8b0a6d0..a05760b5 100644 --- a/docs/data-sources/device_subinterface.md +++ b/docs/data-sources/device_subinterface.md @@ -30,7 +30,6 @@ data "fmc_device_subinterface" "example" { - `domain` (String) The name of the FMC domain - `id` (String) The id of the object -- `interface_name` (String) Name of the parent interface (fmc_device_physical_interface.example.name). - `name` (String) Name of the subinterface in format `interface_name.subinterface_id` (eg. GigabitEthernet0/1.7). ### Read-Only @@ -42,6 +41,7 @@ data "fmc_device_subinterface" "example" { - `enable_anti_spoofing` (Boolean) Enable Anti Spoofing - `enable_sgt_propagate` (Boolean) Indicates whether to propagate SGT. - `enabled` (Boolean) Indicates whether to enable the interface. +- `interface_name` (String) Name of the parent interface (fmc_device_physical_interface.example.name). - `ip_based_monitoring` (Boolean) Indicates whether to enable IP based Monitoring. - `ip_based_monitoring_next_hop` (String) IP address to monitor. - `ip_based_monitoring_type` (String) PPPoE Configuration - PPPoE route metric, [ AUTO, PEER_IPV4, PEER_IPV6, AUTO4, AUTO6 ] diff --git a/docs/data-sources/security_zone.md b/docs/data-sources/security_zone.md index fbbe47ef..e331faae 100644 --- a/docs/data-sources/security_zone.md +++ b/docs/data-sources/security_zone.md @@ -29,5 +29,5 @@ data "fmc_security_zone" "example" { ### Read-Only -- `interface_mode` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. +- `interface_type` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. - `type` (String) Type of the object; this value is always 'SecurityZone'. diff --git a/docs/data-sources/security_zones.md b/docs/data-sources/security_zones.md index b7e832f5..3dbddd61 100644 --- a/docs/data-sources/security_zones.md +++ b/docs/data-sources/security_zones.md @@ -39,5 +39,5 @@ data "fmc_security_zones" "example" { Read-Only: - `id` (String) UUID of the managed Security Zone. -- `interface_mode` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. +- `interface_type` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. - `type` (String) Type of the object; this value is always 'SecurityZone'. diff --git a/docs/resources/bfd_template.md b/docs/resources/bfd_template.md new file mode 100644 index 00000000..fed17a06 --- /dev/null +++ b/docs/resources/bfd_template.md @@ -0,0 +1,69 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_bfd_template Resource - terraform-provider-fmc" +subcategory: "Objects" +description: |- + This resource can manage a BFD Template. +--- + +# fmc_bfd_template (Resource) + +This resource can manage a BFD Template. + +## Example Usage + +```terraform +resource "fmc_bfd_template" "example" { + name = "BFD_Template1" + hop_type = "SINGLE_HOP" + echo = "ENABLED" + interval_time = "MILLISECONDS" + min_transmit = 300 + tx_rx_multiplier = 3 + min_receive = 300 + authentication_password = "Cisco123!" + authentication_key_id = 1 + authentication_type = "MD5" +} +``` + + +## Schema + +### Required + +- `echo` (String) Enables/disables BFD echo. + - Choices: `ENABLED`, `DISABLED` +- `hop_type` (String) The hop type. + - Choices: `SINGLE_HOP`, `MULTI_HOP` +- `name` (String) The name of the bfd template object. + +### Optional + +- `authentication_key_id` (Number) Authentication Key ID + - Range: `0`-`255` +- `authentication_password` (String) Password for BFD Authentication (1-24 characters) +- `authentication_type` (String) Authentication types + - Choices: `MD5`, `METICULOUSMD5`, `METICULOUSSHA1`, `SHA1`, `NONE` +- `domain` (String) The name of the FMC domain +- `interval_time` (String) Interval unit of measurement of time. + - Choices: `MILLISECONDS`, `MICROSECONDS`, `NONE` +- `min_receive` (Number) BFD Minimum Receive unit value in ranges: 50-999 miliseconds, 50000-999000 microseconds + - Range: `50`-`999000` +- `min_transmit` (Number) BFD Minimum Transmit unit value. + - Range: `50`-`999000` +- `tx_rx_multiplier` (Number) BFD Multipler value. + - Range: `3`-`50` + +### Read-Only + +- `id` (String) The id of the object +- `type` (String) Type of the object; this value is always 'BFDTemplate'. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_bfd_template.example "" +``` diff --git a/docs/resources/device_bfd.md b/docs/resources/device_bfd.md new file mode 100644 index 00000000..cb38b8d8 --- /dev/null +++ b/docs/resources/device_bfd.md @@ -0,0 +1,59 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bfd Resource - terraform-provider-fmc" +subcategory: "Device" +description: |- + This resource can manage a Device BFD. +--- + +# fmc_device_bfd (Resource) + +This resource can manage a Device BFD. + +## Example Usage + +```terraform +resource "fmc_device_bfd" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + hop_type = "SINGLE_HOP" + bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + interface_logical_name = "outside" + destination_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + source_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + interface_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Required + +- `bfd_template_id` (String) ID of the BFD Template +- `device_id` (String) UUID of the parent device (fmc_device.example.id). +- `hop_type` (String) BFD Hop type. + - Choices: `SINGLE_HOP`, `MULTI_HOP` + +### Optional + +- `destination_host_object_id` (String) The ID of the destination host object if MULTI_HOP selected. +- `domain` (String) The name of the FMC domain +- `interface_id` (String) ID of the interface of BFD assignment if SINGLE_HOP selected. +- `interface_logical_name` (String) Logical Name of the interface of BFD assignment if SINGLE_HOP selected. +- `slow_timer` (Number) BFD Slow Timer value in range: 1000-30000, default: 1000 + - Range: `1000`-`30000` + - Default value: `1000` +- `source_host_object_id` (String) The ID of the source host object if MULTI_HOP selected. + +### Read-Only + +- `id` (String) The id of the object +- `type` (String) Type of the object; this value is always 'BFDPolicy' + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_device_bfd.example "," +``` diff --git a/docs/resources/device_bgp.md b/docs/resources/device_bgp.md new file mode 100644 index 00000000..47bd92cc --- /dev/null +++ b/docs/resources/device_bgp.md @@ -0,0 +1,260 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bgp Resource - terraform-provider-fmc" +subcategory: "Devices" +description: |- + Under BGP General Settings, BGP has to be enabled and AS Number assigned first. +--- + +# fmc_device_bgp (Resource) + +Under BGP General Settings, BGP has to be enabled and AS Number assigned first. + +## Example Usage + +```terraform +resource "fmc_device_bgp" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + ipv4_default_information_orginate = false + ipv4_auto_aummary = false + ipv4_bgp_supress_inactive = false + ipv4_synchronization = false + ipv4_bgp_redistribute_internal = false + ipv4_external_distance = 20 + ipv4_internal_distance = 200 + ipv4_local_distance = 200 + ipv4_forward_packets_over_multipath_ibgp = 1 + ipv4_forward_packets_over_multipath_ebgp = 1 + ipv4_neighbors = [ + { + neighbor_address = "10.1.1.1" + neighbor_remote_as = "65534" + neighbor_bfd = "SINGLE_HOP" + enable_address_family = true + neighbor_description = "My BGP Peer" + } + ] +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent device (fmc_device.example.id). + +### Optional + +- `domain` (String) The name of the FMC domain +- `ipv4_aggregate_addresses` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_aggregate_addresses)) +- `ipv4_auto_aummary` (Boolean) Summarize subnet routes into network level routes +- `ipv4_bgp_redistribute_internal` (Boolean) Redistribute IBGP into IGP. (Use filtering to limit the number of prefixes that are redistributed) +- `ipv4_bgp_supress_inactive` (Boolean) Suppresing advertise inactive routes +- `ipv4_default_information_orginate` (Boolean) Generate default routes +- `ipv4_external_distance` (Number) Administrative route distance for external routes + - Range: `1`-`255` + - Default value: `20` +- `ipv4_filterings` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_filterings)) +- `ipv4_forward_packets_over_multipath_ebgp` (Number) Number of paths to use for EBGP + - Range: `1`-`8` + - Default value: `1` +- `ipv4_forward_packets_over_multipath_ibgp` (Number) Number of paths to use for IBGP + - Range: `1`-`8` + - Default value: `1` +- `ipv4_internal_distance` (Number) Administrative route distance for internal routes + - Range: `1`-`255` + - Default value: `200` +- `ipv4_learned_route_map_id` (String) Learned Route Map ID +- `ipv4_local_distance` (Number) Administrative route distance for local routes + - Range: `1`-`255` + - Default value: `200` +- `ipv4_neighbors` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors)) +- `ipv4_networks` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_networks)) +- `ipv4_redistributions` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_redistributions)) +- `ipv4_route_injections` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_route_injections)) +- `ipv4_synchronization` (Boolean) Synchronize between BGP and IGP systems + +### Read-Only + +- `as_number` (String) Autonomus System (AS) Number +- `id` (String) The id of the object +- `ipv4_address_family_type` (String) +- `name` (String) Name of the object; this is always 'bgp' +- `type` (String) Type of the object; this is always 'bgp' + + +### Nested Schema for `ipv4_aggregate_addresses` + +Optional: + +- `advertise_map_id` (String) Advertise Map ID +- `attribute_map_id` (String) Attribute Map ID +- `filter` (Boolean) Filter all routes from updates (summary only) +- `generate_as` (Boolean) Generate AS set path information +- `network_id` (String) Network ID +- `suppress_map_id` (String) Suppress Map ID + + + +### Nested Schema for `ipv4_filterings` + +Optional: + +- `access_list_id` (String) Standard Access List ID +- `network_direction` (String) Filtering directrion + - Choices: `incomingroutefilter`, `outgoingroutefilter` +- `prorocol_process` (String) Process ID +- `protocol` (String) Protocol + + + +### Nested Schema for `ipv4_neighbors` + +Optional: + +- `enable_address_family` (Boolean) Enable IPv4 address family + - Default value: `false` +- `neighbor_address` (String) IP address of the BGP neighbor +- `neighbor_authentication_password` (String) Setting password enables authentication. +- `neighbor_bfd` (String) BFD Fallover + - Choices: `SINGLE_HOP`, `MULTI_HOP`, `AUTO_DETECT_HOP`, `NONE` + - Default value: `NONE` +- `neighbor_customized_accept_both_as` (Boolean) Accept either real AS number or local AS number in routes experienced from neighbor +- `neighbor_customized_local_as_number` (String) Customize the AS number for the routes received from neighbor +- `neighbor_customized_no_prepend` (Boolean) Do not prepend local AS number to routes received from neighbor +- `neighbor_customized_replace_as` (Boolean) Replace real AS number with local AS number in routes received from neighbor +- `neighbor_description` (String) Description of the neighbor +- `neighbor_disable_connection_verification` (Boolean) Disable Connection Verification + - Default value: `false` +- `neighbor_filter_access_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_access_lists)) +- `neighbor_filter_as_path_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_as_path_lists)) +- `neighbor_filter_max_prefix` (Number) Maximum number of prefixes allowed from the neighbor + - Range: `1`-`2147483647` +- `neighbor_filter_prefix_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_prefix_lists)) +- `neighbor_filter_restart_interval` (Number) Time interval to restart the maximum prefix limit in Minutes + - Range: `1`-`65535` +- `neighbor_filter_route_map_lists` (Attributes List) (see [below for nested schema](#nestedatt--ipv4_neighbors--neighbor_filter_route_map_lists)) +- `neighbor_filter_threshold_value` (Number) Threshold value for the maximum number of prefixes allowed from the neighbor + - Range: `1`-`100` +- `neighbor_filter_warning_only` (Boolean) Give only warning message when prefix limit exceeded or terminate peering when prefix limit is exceeded. +- `neighbor_generate_default_route_map_id` (String) Generate default routes - Route Map +- `neighbor_hold_time` (Number) Time interval to hold the neighbor in seconds + - Range: `3`-`65535` +- `neighbor_keepalive_interval` (Number) Time interval to send keepalive messages in seconds + - Range: `0`-`65535` +- `neighbor_max_hop_count` (Number) Maximum number of hops to reach the neighbor + - Range: `1`-`255` + - Default value: `1` +- `neighbor_min_hold_time` (Number) Minimum hold time in seconds + - Range: `3`-`65535` +- `neighbor_nexthop_self` (Boolean) Use itself as next hop for this neighbor + - Default value: `false` +- `neighbor_remote_as` (String) AS number of the BGP neighbor +- `neighbor_routes_advertise_exist_nonexist_map_id` (String) Specified route maps are advertised when the prefix exists only in the Advertise Map. +- `neighbor_routes_advertise_map_id` (String) Specified route maps are advertised when the prefix exists in the Advertise Map and Exist Map. +- `neighbor_routes_advertise_map_use_exist` (Boolean) Use Exist Map or Non-Exist Map +- `neighbor_routes_advertisement_interval` (Number) Time interval to advertise routes in seconds + - Range: `0`-`600` + - Default value: `0` +- `neighbor_routes_remove_private_as` (Boolean) Remove private AS numbers from outgoing routing updates + - Default value: `false` +- `neighbor_send_community_attribute` (Boolean) Send Community attribute to this neighbor + - Default value: `false` +- `neighbor_shutdown` (Boolean) Shutdown administratively + - Default value: `false` +- `neighbor_tcp_mtu_path_discovery` (Boolean) Use TCP path MTU discovery. + - Default value: `false` +- `neighbor_tcp_transport_mode` (Boolean) True set it to active, False to passive. + - Default value: `false` +- `neighbor_version` (String) Set BPG version: 0 - default, 4 - IPv4 + - Choices: `0`, `4` + - Default value: `0` +- `neighbor_weight` (Number) Weight of the neighbor + - Range: `0`-`65535` + - Default value: `0` +- `update_source_interface_id` (String) Interface ID for the update source + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_access_lists` + +Optional: + +- `access_list_id` (String) Access List ID +- `update_direction` (String) Filter direction + - Choices: `IN`, `OUT` + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_as_path_lists` + +Optional: + +- `as_path_id` (String) AS Path ID +- `update_direction` (String) Filter direction + - Choices: `IN`, `OUT` + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_prefix_lists` + +Optional: + +- `prefix_list_id` (String) Route Map ID +- `update_direction` (String) Filter direction + - Choices: `IN`, `OUT` + + + +### Nested Schema for `ipv4_neighbors.neighbor_filter_route_map_lists` + +Optional: + +- `route_map_id` (String) Route Map ID +- `update_direction` (String) Filter direction + - Choices: `IN`, `OUT` + + + + +### Nested Schema for `ipv4_networks` + +Optional: + +- `network_id` (String) Network object ID +- `route_map_id` (String) Route Map ID + + + +### Nested Schema for `ipv4_redistributions` + +Optional: + +- `match_external1` (Boolean) Match OSPF External 1 metrics +- `match_external2` (Boolean) Match OSPF External 2 metrics +- `match_internal` (Boolean) Match OSPF Internal metrics +- `match_nssa_external1` (Boolean) Match OSPF NSSA External 1 metrics +- `match_nssa_external2` (Boolean) Match OSPF NSSA External 2 metrics +- `metric` (Number) Metric value + - Range: `0`-`4294967295` +- `process_id` (String) process ID +- `route_map_id` (String) Route Map ID +- `source_protocol` (String) Protocol to redistribute + - Choices: `RedistributeConnected`, `RedistributeStatic`, `RedistributeOSPF`, `RedistributeEIGRP` + + + +### Nested Schema for `ipv4_route_injections` + +Optional: + +- `exist_route_map_id` (String) Exist Route Map ID +- `inject_route_map_id` (String) Inject Route Map ID + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_device_bgp.example "," +``` diff --git a/docs/resources/device_bgp_general_settings.md b/docs/resources/device_bgp_general_settings.md new file mode 100644 index 00000000..66ecb3b4 --- /dev/null +++ b/docs/resources/device_bgp_general_settings.md @@ -0,0 +1,84 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_bgp_general_settings Resource - terraform-provider-fmc" +subcategory: "Devices" +description: |- + This resource can manage a Device BGP General Settings. +--- + +# fmc_device_bgp_general_settings (Resource) + +This resource can manage a Device BGP General Settings. + +## Example Usage + +```terraform +resource "fmc_device_bgp_general_settings" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + as_number = "65535" + router_id = "AUTOMATIC" + scanning_interval = 60 + as_number_in_path_attribute = 50 + tcp_path_mtu_discovery = true + reset_session_upon_failover = true + enforce_first_peer_as = true + use_dot_notation = false +} +``` + + +## Schema + +### Required + +- `as_number` (String) Autonomous System (AS) number in asplain or asdot format +- `device_id` (String) UUID of the parent device (fmc_device.example.id). + +### Optional + +- `aggregate_timer` (Number) Interval at which BGP routes will be aggregated or to disable timer-based router aggregation (in seconds). + - Range: `6`-`60` +- `as_number_in_path_attribute` (Number) Range to discard routes that have as-path segments that exceed a specified value. + - Range: `1`-`254` +- `compare_med_from_different_neighbors` (Boolean) Allow comparing MED from different neighbors +- `compare_router_id_in_path` (Boolean) Compare Router ID for identical EBGP paths +- `default_local_preference` (Number) Default local preference + - Range: `0`-`4294967295` +- `domain` (String) The name of the FMC domain +- `enforce_first_peer_as` (Boolean) Discard updates received from an external BGP (eBGP) peers that do not list their autonomous system (AS) number. +- `graceful_restart` (Boolean) Enable graceful restart +- `graceful_restart_restart_time` (Number) Graceful Restart Time in seconds + - Range: `1`-`3600` +- `graceful_restart_stale_path_time` (Number) Stalepath Time in seconds + - Range: `1`-`3600` +- `hold_time` (Number) Hold time in seconds + - Range: `0`-`65535` +- `keepalive_interval` (Number) Keepalive interval in seconds + - Range: `0`-`65535` +- `log_neighbor_changes` (Boolean) Enable logging of BGP neighbor status changes. +- `min_hold_time` (Number) Minimum hold time (0 or 3-65535 seconds) + - Range: `0`-`65535` +- `missing_med_as_best` (Boolean) Treat missing MED as the best preferred path +- `next_hop_address_tracking` (Boolean) Enable next hop address tracking +- `next_hop_delay_interval` (Number) Next hop delay interval in seconds + - Range: `0`-`100` +- `pick_best_med` (Boolean) Pick the best-MED path among paths advertised by neighbor AS +- `reset_session_upon_failover` (Boolean) Reset session upon failover +- `router_id` (String) String value for the routerID. Possible values can be 'AUTOMATIC' or valid ipv4 address +- `scanning_interval` (Number) Scanning interval of BGP routers for next hop validation in Seconds. + - Range: `5`-`60` +- `tcp_path_mtu_discovery` (Boolean) Use TCP path MTU discovery. +- `use_dot_notation` (Boolean) Change format of BGP 4-byte autonomous system numbers from asplain (decimal values) to dot notation. + +### Read-Only + +- `id` (String) The id of the object +- `name` (String) Object name; Always set to 'AsaBGPGeneralTable' + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_device_bgp_general_settings.example "," +``` diff --git a/docs/resources/device_ha_pair_monitoring.md b/docs/resources/device_ha_pair_monitoring.md new file mode 100644 index 00000000..f6a2782a --- /dev/null +++ b/docs/resources/device_ha_pair_monitoring.md @@ -0,0 +1,66 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_ha_pair_monitoring Resource - terraform-provider-fmc" +subcategory: "Device" +description: |- + This resource can manage a Device HA Pair Monitoring. +--- + +# fmc_device_ha_pair_monitoring (Resource) + +This resource can manage a Device HA Pair Monitoring. + +## Example Usage + +```terraform +resource "fmc_device_ha_pair_monitoring" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + logical_name = "outside" + monitor_interface = true + ipv4_standby_address = "10.1.1.2" + ipv6_addresses = [ + { + active_address = "2006::1/30" + standby_address = "2006::2" + } + ] +} +``` + + +## Schema + +### Required + +- `device_id` (String) UUID of the parent HA device (fmc_device.example.id). +- `logical_name` (String) Logical Name of the monitored interface. +- `monitor_interface` (Boolean) Monitor this interface for failures. + +### Optional + +- `domain` (String) The name of the FMC domain +- `ipv4_standby_address` (String) Standby IPv4 address. It has to be in the same subnet as primaty IP configured on this interface. +- `ipv6_addresses` (Attributes List) (see [below for nested schema](#nestedatt--ipv6_addresses)) + +### Read-Only + +- `id` (String) The id of the object +- `ipv4_active_address` (String) Active IPv4 address from the interface. +- `ipv4_netmask` (String) IPv4 Network Mask assigned on the interface. +- `type` (String) Type of the resource. + + +### Nested Schema for `ipv6_addresses` + +Optional: + +- `active_address` (String) Active IPv6 address with prefix. Address has to be configured on the interface. +- `standby_address` (String) Standby IPv6 address. Address has to be from the same subnet as active IPv6 address. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_device_ha_pair_monitoring.example "," +``` diff --git a/docs/resources/network.md b/docs/resources/network.md index 49d5dd53..a3af78c4 100644 --- a/docs/resources/network.md +++ b/docs/resources/network.md @@ -34,12 +34,11 @@ resource "fmc_network" "example" { - `description` (String) Description - `domain` (String) The name of the FMC domain - `overridable` (Boolean) Whether the object values can be overridden. -- `type` (String) Type of the object; this value is always 'Network'. - - Default value: `Network` ### Read-Only - `id` (String) The id of the object +- `type` (String) Type of the object; this value is always 'Network'. ## Import diff --git a/docs/resources/networks.md b/docs/resources/networks.md index e75075c4..b0a99d81 100644 --- a/docs/resources/networks.md +++ b/docs/resources/networks.md @@ -49,12 +49,11 @@ Optional: - `description` (String) Optional user-created description. - `overridable` (Boolean) Indicates whether object values can be overridden. -- `type` (String) Type of the object; this value is always 'Network'. - - Default value: `Network` Read-Only: - `id` (String) UUID of the managed Network. +- `type` (String) Type of the object; this value is always 'Network'. ## Import diff --git a/docs/resources/port_group.md b/docs/resources/port_group.md index 7f248864..c33164b1 100644 --- a/docs/resources/port_group.md +++ b/docs/resources/port_group.md @@ -38,12 +38,11 @@ resource "fmc_port_group" "example" { - `description` (String) Optional user-created description. - `domain` (String) The name of the FMC domain - `overridable` (Boolean) Indicates whether object values can be overridden. -- `type` (String) Type of the object; this value is always 'PortObjectGroup'. - - Default value: `PortObjectGroup` ### Read-Only - `id` (String) The id of the object +- `type` (String) Type of the object; this value is always 'PortObjectGroup'. ### Nested Schema for `objects` diff --git a/docs/resources/port_groups.md b/docs/resources/port_groups.md index bc251695..1b53465d 100644 --- a/docs/resources/port_groups.md +++ b/docs/resources/port_groups.md @@ -54,12 +54,11 @@ Optional: - `description` (String) Optional user-created description. - `overridable` (Boolean) Indicates whether object values can be overridden. -- `type` (String) Type of the object; this value is always 'PortObjectGroup'. - - Default value: `PortObjectGroup` Read-Only: - `id` (String) UUID of the managed Port Groups. +- `type` (String) Type of the object; this value is always 'PortObjectGroup'. ### Nested Schema for `items.objects` diff --git a/docs/resources/security_zone.md b/docs/resources/security_zone.md index 44ee1f97..23124bd0 100644 --- a/docs/resources/security_zone.md +++ b/docs/resources/security_zone.md @@ -15,7 +15,7 @@ This resource can manage a Security Zone. ```terraform resource "fmc_security_zone" "example" { name = "security_zone_1" - interface_mode = "ROUTED" + interface_type = "ROUTED" } ``` @@ -24,19 +24,18 @@ resource "fmc_security_zone" "example" { ### Required -- `interface_mode` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. +- `interface_type` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. - Choices: `PASSIVE`, `INLINE`, `SWITCHED`, `ROUTED`, `ASA` - `name` (String) User-provided resource name. ### Optional - `domain` (String) The name of the FMC domain -- `type` (String) Type of the object; this value is always 'SecurityZone'. - - Default value: `SecurityZone` ### Read-Only - `id` (String) The id of the object +- `type` (String) Type of the object; this value is always 'SecurityZone'. ## Import diff --git a/docs/resources/security_zones.md b/docs/resources/security_zones.md index f3056696..627e086b 100644 --- a/docs/resources/security_zones.md +++ b/docs/resources/security_zones.md @@ -16,7 +16,7 @@ This plural resource manages a bulk of Security Zones. The FMC API supports quic resource "fmc_security_zones" "example" { items = { security_zone_1 = { - interface_mode = "ROUTED" + interface_type = "ROUTED" } } } @@ -42,17 +42,13 @@ resource "fmc_security_zones" "example" { Required: -- `interface_mode` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. +- `interface_type` (String) The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces. - Choices: `PASSIVE`, `INLINE`, `SWITCHED`, `ROUTED`, `ASA` -Optional: - -- `type` (String) Type of the object; this value is always 'SecurityZone'. - - Default value: `SecurityZone` - Read-Only: - `id` (String) UUID of the managed Security Zone. +- `type` (String) Type of the object; this value is always 'SecurityZone'. ## Import diff --git a/examples/data-sources/fmc_bfd_template/data-source.tf b/examples/data-sources/fmc_bfd_template/data-source.tf new file mode 100644 index 00000000..e977873f --- /dev/null +++ b/examples/data-sources/fmc_bfd_template/data-source.tf @@ -0,0 +1,3 @@ +data "fmc_bfd_template" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_bgd_template/data-source.tf b/examples/data-sources/fmc_bgd_template/data-source.tf new file mode 100644 index 00000000..87278826 --- /dev/null +++ b/examples/data-sources/fmc_bgd_template/data-source.tf @@ -0,0 +1,3 @@ +data "fmc_bgd_template" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_bfd/data-source.tf b/examples/data-sources/fmc_device_bfd/data-source.tf new file mode 100644 index 00000000..dbc96a7c --- /dev/null +++ b/examples/data-sources/fmc_device_bfd/data-source.tf @@ -0,0 +1,4 @@ +data "fmc_device_bfd" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_bgp/data-source.tf b/examples/data-sources/fmc_device_bgp/data-source.tf new file mode 100644 index 00000000..b7c2fcdf --- /dev/null +++ b/examples/data-sources/fmc_device_bgp/data-source.tf @@ -0,0 +1,4 @@ +data "fmc_device_bgp" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_bgp_general_settings/data-source.tf b/examples/data-sources/fmc_device_bgp_general_settings/data-source.tf new file mode 100644 index 00000000..e991debc --- /dev/null +++ b/examples/data-sources/fmc_device_bgp_general_settings/data-source.tf @@ -0,0 +1,4 @@ +data "fmc_device_bgp_general_settings" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_bgp_generel_settings/data-source.tf b/examples/data-sources/fmc_device_bgp_generel_settings/data-source.tf new file mode 100644 index 00000000..cd1c0cfb --- /dev/null +++ b/examples/data-sources/fmc_device_bgp_generel_settings/data-source.tf @@ -0,0 +1,4 @@ +data "fmc_device_bgp_generel_settings" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_ha_pair/data-source.tf b/examples/data-sources/fmc_device_ha_pair/data-source.tf new file mode 100644 index 00000000..aac62b48 --- /dev/null +++ b/examples/data-sources/fmc_device_ha_pair/data-source.tf @@ -0,0 +1,3 @@ +data "fmc_device_ha_pair" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/data-sources/fmc_device_ha_pair_monitoring/data-source.tf b/examples/data-sources/fmc_device_ha_pair_monitoring/data-source.tf new file mode 100644 index 00000000..cb03d3e0 --- /dev/null +++ b/examples/data-sources/fmc_device_ha_pair_monitoring/data-source.tf @@ -0,0 +1,4 @@ +data "fmc_device_ha_pair_monitoring" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/resources/fmc_bfd_template/import.sh b/examples/resources/fmc_bfd_template/import.sh new file mode 100644 index 00000000..ed00cc19 --- /dev/null +++ b/examples/resources/fmc_bfd_template/import.sh @@ -0,0 +1 @@ +terraform import fmc_bfd_template.example "" diff --git a/examples/resources/fmc_bfd_template/resource.tf b/examples/resources/fmc_bfd_template/resource.tf new file mode 100644 index 00000000..42141988 --- /dev/null +++ b/examples/resources/fmc_bfd_template/resource.tf @@ -0,0 +1,12 @@ +resource "fmc_bfd_template" "example" { + name = "BFD_Template1" + hop_type = "SINGLE_HOP" + echo = "ENABLED" + interval_time = "MILLISECONDS" + min_transmit = 300 + tx_rx_multiplier = 3 + min_receive = 300 + authentication_password = "Cisco123!" + authentication_key_id = 1 + authentication_type = "MD5" +} diff --git a/examples/resources/fmc_bgd_template/import.sh b/examples/resources/fmc_bgd_template/import.sh new file mode 100644 index 00000000..8f7c8880 --- /dev/null +++ b/examples/resources/fmc_bgd_template/import.sh @@ -0,0 +1 @@ +terraform import fmc_bgd_template.example "" diff --git a/examples/resources/fmc_bgd_template/resource.tf b/examples/resources/fmc_bgd_template/resource.tf new file mode 100644 index 00000000..ad675aac --- /dev/null +++ b/examples/resources/fmc_bgd_template/resource.tf @@ -0,0 +1,9 @@ +resource "fmc_bgd_template" "example" { + name = "BFD_Template1" + hop_type = "SINGLE_HOP" + echo = "ENABLED" + interval_time = "MILLISECONDS" + min_transmit = 100000 + tx_rx_multiplier = 3 + min_receive = 100000 +} diff --git a/examples/resources/fmc_device_bfd/import.sh b/examples/resources/fmc_device_bfd/import.sh new file mode 100644 index 00000000..718eaaf1 --- /dev/null +++ b/examples/resources/fmc_device_bfd/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_bfd.example "," diff --git a/examples/resources/fmc_device_bfd/resource.tf b/examples/resources/fmc_device_bfd/resource.tf new file mode 100644 index 00000000..fb7b2497 --- /dev/null +++ b/examples/resources/fmc_device_bfd/resource.tf @@ -0,0 +1,9 @@ +resource "fmc_device_bfd" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + hop_type = "SINGLE_HOP" + bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + interface_logical_name = "outside" + destination_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + source_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + interface_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/resources/fmc_device_bgp/import.sh b/examples/resources/fmc_device_bgp/import.sh new file mode 100644 index 00000000..34790e31 --- /dev/null +++ b/examples/resources/fmc_device_bgp/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_bgp.example "," diff --git a/examples/resources/fmc_device_bgp/resource.tf b/examples/resources/fmc_device_bgp/resource.tf new file mode 100644 index 00000000..68231751 --- /dev/null +++ b/examples/resources/fmc_device_bgp/resource.tf @@ -0,0 +1,22 @@ +resource "fmc_device_bgp" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + ipv4_default_information_orginate = false + ipv4_auto_aummary = false + ipv4_bgp_supress_inactive = false + ipv4_synchronization = false + ipv4_bgp_redistribute_internal = false + ipv4_external_distance = 20 + ipv4_internal_distance = 200 + ipv4_local_distance = 200 + ipv4_forward_packets_over_multipath_ibgp = 1 + ipv4_forward_packets_over_multipath_ebgp = 1 + ipv4_neighbors = [ + { + neighbor_address = "10.1.1.1" + neighbor_remote_as = "65534" + neighbor_bfd = "SINGLE_HOP" + enable_address_family = true + neighbor_description = "My BGP Peer" + } + ] +} diff --git a/examples/resources/fmc_device_bgp_general_settings/import.sh b/examples/resources/fmc_device_bgp_general_settings/import.sh new file mode 100644 index 00000000..9f728317 --- /dev/null +++ b/examples/resources/fmc_device_bgp_general_settings/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_bgp_general_settings.example "," diff --git a/examples/resources/fmc_device_bgp_general_settings/resource.tf b/examples/resources/fmc_device_bgp_general_settings/resource.tf new file mode 100644 index 00000000..8605b5f4 --- /dev/null +++ b/examples/resources/fmc_device_bgp_general_settings/resource.tf @@ -0,0 +1,11 @@ +resource "fmc_device_bgp_general_settings" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + as_number = "65535" + router_id = "AUTOMATIC" + scanning_interval = 60 + as_number_in_path_attribute = 50 + tcp_path_mtu_discovery = true + reset_session_upon_failover = true + enforce_first_peer_as = true + use_dot_notation = false +} diff --git a/examples/resources/fmc_device_bgp_generel_settings/import.sh b/examples/resources/fmc_device_bgp_generel_settings/import.sh new file mode 100644 index 00000000..c5a3225f --- /dev/null +++ b/examples/resources/fmc_device_bgp_generel_settings/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_bgp_generel_settings.example "," diff --git a/examples/resources/fmc_device_bgp_generel_settings/resource.tf b/examples/resources/fmc_device_bgp_generel_settings/resource.tf new file mode 100644 index 00000000..ce00b414 --- /dev/null +++ b/examples/resources/fmc_device_bgp_generel_settings/resource.tf @@ -0,0 +1,5 @@ +resource "fmc_device_bgp_generel_settings" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + as_number = "65535" + router_id = "AUTOMATIC" +} diff --git a/examples/resources/fmc_device_ha_pair/import.sh b/examples/resources/fmc_device_ha_pair/import.sh new file mode 100644 index 00000000..224ab835 --- /dev/null +++ b/examples/resources/fmc_device_ha_pair/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_ha_pair.example "" diff --git a/examples/resources/fmc_device_ha_pair/resource.tf b/examples/resources/fmc_device_ha_pair/resource.tf new file mode 100644 index 00000000..62255af9 --- /dev/null +++ b/examples/resources/fmc_device_ha_pair/resource.tf @@ -0,0 +1,27 @@ +resource "fmc_device_ha_pair" "example" { + name = "FTD_HA" + primary_device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + secondary_device_id = "96d24097-41c4-4332-a4d0-a8c07ac08482" + is_encryption_enabled = false + use_same_link_for_failovers = false + shared_key = "cisco123" + enc_key_generation_scheme = "CUSTOM" + lan_failover_standby_ip = "1.1.1.2" + lan_failover_active_ip = "1.1.1.1" + lan_failover_name = "LAN-INTERFACE" + lan_failover_subnet_mask = "255.255.255.0" + lan_failover_ipv6_addr = false + lan_failover_interface_name = "GigabitEthernet0/0" + lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470" + lan_failover_interface_type = "PhysicalInterface" + stateful_failover_standby_ip = "10.10.10.2" + stateful_failover_active_ip = "10.10.10.1" + stateful_failover_name = "Stateful-INTERFACE" + stateful_failover_subnet_mask = "255.255.255.0" + stateful_failover_ipv6_addr = false + stateful_failover_interface_name = "GigabitEthernet0/0" + stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470" + stateful_failover_interface_type = "PhysicalInterface" + action = "SWITCH" + force_break = false +} diff --git a/examples/resources/fmc_device_ha_pair_monitoring/import.sh b/examples/resources/fmc_device_ha_pair_monitoring/import.sh new file mode 100644 index 00000000..72f4d65f --- /dev/null +++ b/examples/resources/fmc_device_ha_pair_monitoring/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_ha_pair_monitoring.example "," diff --git a/examples/resources/fmc_device_ha_pair_monitoring/resource.tf b/examples/resources/fmc_device_ha_pair_monitoring/resource.tf new file mode 100644 index 00000000..f4b73367 --- /dev/null +++ b/examples/resources/fmc_device_ha_pair_monitoring/resource.tf @@ -0,0 +1,12 @@ +resource "fmc_device_ha_pair_monitoring" "example" { + device_id = "76d24097-41c4-4558-a4d0-a8c07ac08470" + logical_name = "outside" + monitor_interface = true + ipv4_standby_address = "10.1.1.2" + ipv6_addresses = [ + { + active_address = "2006::1/30" + standby_address = "2006::2" + } + ] +} diff --git a/examples/resources/fmc_security_zone/resource.tf b/examples/resources/fmc_security_zone/resource.tf index 4ddb38be..7ee3c662 100644 --- a/examples/resources/fmc_security_zone/resource.tf +++ b/examples/resources/fmc_security_zone/resource.tf @@ -1,4 +1,4 @@ resource "fmc_security_zone" "example" { name = "security_zone_1" - interface_mode = "ROUTED" + interface_type = "ROUTED" } diff --git a/examples/resources/fmc_security_zones/resource.tf b/examples/resources/fmc_security_zones/resource.tf index 2a58a33d..f168b415 100644 --- a/examples/resources/fmc_security_zones/resource.tf +++ b/examples/resources/fmc_security_zones/resource.tf @@ -1,7 +1,7 @@ resource "fmc_security_zones" "example" { items = { security_zone_1 = { - interface_mode = "ROUTED" + interface_type = "ROUTED" } } } diff --git a/gen/definitions/access_control_policy.yaml b/gen/definitions/access_control_policy.yaml index 0769b365..b82e21fd 100644 --- a/gen/definitions/access_control_policy.yaml +++ b/gen/definitions/access_control_policy.yaml @@ -1,7 +1,6 @@ --- name: Access Control Policy rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/accesspolicies -data_source_name_query: true doc_category: Policy attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: mandatory: true description: The name of the access control policy. example: POLICY1 + data_source_query: true - model_name: description type: String description: Description diff --git a/gen/definitions/bfd_template.yaml b/gen/definitions/bfd_template.yaml new file mode 100644 index 00000000..22e48d07 --- /dev/null +++ b/gen/definitions/bfd_template.yaml @@ -0,0 +1,79 @@ +--- +name: BFD Template +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/bfdtemplates +doc_category: Objects +attributes: + - model_name: name + type: String + mandatory: true + description: The name of the bfd template object. + example: BFD_Template1 + data_source_query: true + - model_name: type + type: String + description: Type of the object; this value is always 'BFDTemplate'. + computed: true + - model_name: hopType + type: String + mandatory: true + description: The hop type. + enum_values: [ SINGLE_HOP, MULTI_HOP ] + example: "SINGLE_HOP" + - model_name: echo + type: String + mandatory: true + description: "Enables/disables BFD echo." + enum_values: [ ENABLED, DISABLED ] + example: "ENABLED" + - model_name: txRxInterval + tf_name: interval_time + type: String + description: Interval unit of measurement of time. + enum_values: [ MILLISECONDS, MICROSECONDS, NONE ] + example: "MILLISECONDS" + - model_name: minTransmit + type: Int64 + description: BFD Minimum Transmit unit value. + min_int: 50 + max_int: 999000 + example: 300 + - model_name: txRxMultiplier + type: Int64 + description: BFD Multipler value. + min_int: 3 + max_int: 50 + example: 3 + - model_name: minReceive + type: Int64 + description: "BFD Minimum Receive unit value in ranges: 50-999 miliseconds, 50000-999000 microseconds" + min_int: 50 + max_int: 999000 + example: 300 + - model_name: authKey + tf_name: authentication_password + data_path: [authentication] + type: String + description: "Password for BFD Authentication (1-24 characters)" + example: "Cisco123!" + - model_name: authKeyId + tf_name: authentication_key_id + data_path: [authentication] + type: Int64 + description: Authentication Key ID + min_int: 0 + max_int: 255 + example: "1" + - model_name: authType + tf_name: authentication_type + data_path: [authentication] + type: String + description: "Authentication types" + example: "MD5" + enum_values: [MD5, METICULOUSMD5, METICULOUSSHA1, SHA1, NONE] + #- model_name: pwdEncryption + # tf_name: authentication_encryption + # data_path: [authentication] + # type: String + # description: "Authentication types: (MD5, METICULOUSMD5, METICULOUSSHA1, SHA1, NONE)" + # example: "NONE" + # enum_values: [UN_ENCRYPTED, ENCRYPTED, NONE] \ No newline at end of file diff --git a/gen/definitions/device.yaml b/gen/definitions/device.yaml index 9be227f6..95aaf147 100644 --- a/gen/definitions/device.yaml +++ b/gen/definitions/device.yaml @@ -1,7 +1,6 @@ --- name: Device rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords -data_source_name_query: true doc_category: Devices test_tags: [FTD_ADDR] attributes: @@ -11,6 +10,7 @@ attributes: description: "User-specified name, must be unique. Example: 'Device 01 - 192.168.0.152'" example: device1 minimum_test_value: '"device1min"' + data_source_query: true - model_name: hostName type: String description: Hostname or IP address of the device. Either the host_name or nat_id must be present. @@ -45,7 +45,6 @@ attributes: type: String description: Type of the device; this value is always 'Device'. exclude_example: true - requires_replace: true default_value: Device example: Device - tf_name: access_policy_id diff --git a/gen/definitions/device_bfd.yaml b/gen/definitions/device_bfd.yaml new file mode 100644 index 00000000..3a747134 --- /dev/null +++ b/gen/definitions/device_bfd.yaml @@ -0,0 +1,67 @@ +--- +name: Device BFD +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bfdpolicies +doc_category: Device +test_tags: [TF_VAR_device_id] +attributes: + - tf_name: device_id + type: String + reference: true + description: UUID of the parent device (fmc_device.example.id). + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + test_value: var.device_id + - model_name: type + type: String + computed: true + description: Type of the object; this value is always 'BFDPolicy' +# General + - model_name: hopType + description: BFD Hop type. + mandatory: true + enum_values: [ SINGLE_HOP, MULTI_HOP ] + type: String + example: SINGLE_HOP + - model_name: id + tf_name: bfd_template_id + data_path: [template] + mandatory: true + type: String + description: ID of the BFD Template + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + - model_name: ifname + data_path: [interface] + tf_name: interface_logical_name + description: Logical Name of the interface of BFD assignment if SINGLE_HOP selected. + type: String + example: "outside" + data_source_query: true + - model_name: id + data_path: [destinationAddress] + tf_name: destination_host_object_id + description: The ID of the destination host object if MULTI_HOP selected. + type: String + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + - model_name: id + data_path: [sourceAddress] + tf_name: source_host_object_id + description: The ID of the source host object if MULTI_HOP selected. + type: String + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + - model_name: id + data_path: [interface] + tf_name: interface_id + description: ID of the interface of BFD assignment if SINGLE_HOP selected. + type: String + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + - model_name: slowTimer + type: Int64 + description: "BFD Slow Timer value in range: 1000-30000, default: 1000" + min_int: 1000 + max_int: 30000 + default_value: 1000 + exclude_example: true + +test_prerequisites: |- + variable "device_id" { default = null } // tests will set $TF_VAR_device_id + + \ No newline at end of file diff --git a/gen/definitions/device_bgp.yaml b/gen/definitions/device_bgp.yaml new file mode 100644 index 00000000..03945087 --- /dev/null +++ b/gen/definitions/device_bgp.yaml @@ -0,0 +1,681 @@ +--- +name: Device BGP +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bgp +res_description: Under BGP General Settings, BGP has to be enabled and AS Number assigned first. +doc_category: Devices +test_tags: [TF_VAR_device_id] +attributes: + - model_name: device_id + type: String + reference: true + requires_replace: true + description: UUID of the parent device (fmc_device.example.id). + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + test_value: var.device_id + - model_name: name + type: String + description: Name of the object; this is always 'bgp' + computed: true + - model_name: type + type: String + description: Type of the object; this is always 'bgp' + computed: true + - model_name: asNumber + type: String + description: Autonomus System (AS) Number + computed: true + data_source_query: true +# BGP - IPv4 - General + - model_name: type + tf_name: ipv4_address_family_type + data_path: [addressFamilyIPv4] + type: String + computed: true + - model_name: id + tf_name: ipv4_learned_route_map_id + data_path: [addressFamilyIPv4, aftableMap] + type: String + description: Learned Route Map ID + exclude_test: true + exclude_example: true + - model_name: defaultInformationOrginate + tf_name: ipv4_default_information_orginate + data_path: [addressFamilyIPv4] + type: Bool + example: "false" + description: Generate default routes + - model_name: autoSummary + tf_name: ipv4_auto_aummary + data_path: [addressFamilyIPv4] + type: Bool + example: "false" + description: Summarize subnet routes into network level routes + - model_name: bgpSupressInactive + tf_name: ipv4_bgp_supress_inactive + data_path: [addressFamilyIPv4] + type: Bool + example: "false" + description: Suppresing advertise inactive routes + - model_name: synchronization + tf_name: ipv4_synchronization + data_path: [addressFamilyIPv4] + type: Bool + example: "false" + description: Synchronize between BGP and IGP systems + - model_name: bgpRedistributeInternal + tf_name: ipv4_bgp_redistribute_internal + data_path: [addressFamilyIPv4] + type: Bool + example: "false" + description: Redistribute IBGP into IGP. (Use filtering to limit the number of prefixes that are redistributed) + - model_name: externalDistance + tf_name: ipv4_external_distance + data_path: [addressFamilyIPv4, distance] + type: Int64 + description: Administrative route distance for external routes + min_int: 1 + max_int: 255 + default_value: 20 + example: 20 + - model_name: internalDistance + tf_name: ipv4_internal_distance + data_path: [addressFamilyIPv4, distance] + type: Int64 + description: Administrative route distance for internal routes + min_int: 1 + max_int: 255 + default_value: 200 + example: 200 + - model_name: localDistance + tf_name: ipv4_local_distance + data_path: [addressFamilyIPv4, distance] + type: Int64 + description: Administrative route distance for local routes + min_int: 1 + max_int: 255 + example: 200 + default_value: 200 + - model_name: ibgp + tf_name: ipv4_forward_packets_over_multipath_ibgp ## ipv4_number_of_ibgp_paths + data_path: [addressFamilyIPv4] + type: Int64 + description: Number of paths to use for IBGP + min_int: 1 + max_int: 8 + example: 1 + default_value: 1 + - model_name: ebgp + tf_name: ipv4_forward_packets_over_multipath_ebgp ## ipv4_number_of_ebgp_paths + data_path: [addressFamilyIPv4] + type: Int64 + description: Number of paths to use for EBGP + min_int: 1 + max_int: 8 + example: 1 + default_value: 1 +# BGP - IPv4 - Neighbor + - model_name: neighbors + tf_name: ipv4_neighbors + data_path: [addressFamilyIPv4] + type: List + attributes: + - model_name: ipv4Address + tf_name: neighbor_address + type: String + description: IP address of the BGP neighbor + id: true + example: "10.1.1.1" + - model_name: remoteAs + tf_name: neighbor_remote_as + type: String + description: AS number of the BGP neighbor + id: true + example: "65534" + - model_name: fallOverBFD + data_path: [neighborGeneral] + tf_name: neighbor_bfd + type: String + description: BFD Fallover + enum_values: [ SINGLE_HOP, MULTI_HOP, AUTO_DETECT_HOP, NONE ] + example: "SINGLE_HOP" + default_value: "NONE" + - model_name: id + data_path: [neighborGeneral, updateSource] + tf_name: update_source_interface_id + type: String + description: Interface ID for the update source + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + exclude_test: true + exclude_example: true + - model_name: enableAddress + data_path: [neighborGeneral] + tf_name: enable_address_family + type: Bool + description: Enable IPv4 address family + default_value: "false" + example: "true" + - model_name: shutdown + data_path: [neighborGeneral] + tf_name: neighbor_shutdown + description: Shutdown administratively + type: Bool + default_value: "false" + example: "false" + exclude_example: true + - model_name: description + tf_name: neighbor_description + data_path: [neighborGeneral] + type: String + description: Description of the neighbor + example: "My BGP Peer" +# BGP - IPv4 - Neighbor - Filtering Routes + - model_name: neighborDistributeLists + tf_name: neighbor_filter_access_lists + data_path: [neighborFiltering] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: access_list_id + data_path: [accessList] + type: String + description: Access List ID + exclude_test: true + exclude_example: true + - model_name: filterUpdateAction + tf_name: update_direction + type: String + description: Filter direction + enum_values: [ IN, OUT ] + exclude_test: true + exclude_example: true + - model_name: neighborRouteMap + tf_name: neighbor_filter_route_map_lists + data_path: [neighborFiltering] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: route_map_id + data_path: [RouteMap] + type: String + description: Route Map ID + exclude_test: true + exclude_example: true + - model_name: filterUpdateAction + tf_name: update_direction + type: String + description: Filter direction + enum_values: [ IN, OUT ] + exclude_test: true + exclude_example: true + - model_name: ipv4PrefixListFilter + tf_name: neighbor_filter_prefix_lists + data_path: [neighborFiltering] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: prefix_list_id + data_path: [ipv4PrefixList] + type: String + description: Route Map ID + exclude_test: true + exclude_example: true + - model_name: filterUpdateAction + tf_name: update_direction + type: String + description: Filter direction + enum_values: [ IN, OUT ] + exclude_test: true + exclude_example: true + - model_name: neighborFilterList + tf_name: neighbor_filter_as_path_lists + data_path: [neighborFilterList] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: filterUpdateAction + tf_name: update_direction + type: String + description: Filter direction + enum_values: [ IN, OUT ] + exclude_test: true + exclude_example: true + - model_name: id + tf_name: as_path_id + data_path: [asPathList] + type: String + description: AS Path ID + exclude_test: true + exclude_example: true + - model_name: maxPrefixLimit + data_path: [neighborFiltering, neighborMaximumPrefix] + tf_name: neighbor_filter_max_prefix + type: Int64 + description: Maximum number of prefixes allowed from the neighbor + min_int: 1 + max_int: 2147483647 + example: 1 + exclude_example: true + - model_name: warningOnly + data_path: [neighborFiltering, neighborMaximumPrefix] + tf_name: neighbor_filter_warning_only + type: Bool + description: Give only warning message when prefix limit exceeded or terminate peering when prefix limit is exceeded. + example: true + exclude_example: true + - model_name: thresholdValue + data_path: [neighborFiltering, neighborMaximumPrefix] + tf_name: neighbor_filter_threshold_value + type: Int64 + description: Threshold value for the maximum number of prefixes allowed from the neighbor + min_int: 1 + max_int: 100 + example: 1 + exclude_example: true + - model_name: restartInterval + data_path: [neighborFiltering, neighborMaximumPrefix] + tf_name: neighbor_filter_restart_interval + type: Int64 + description: Time interval to restart the maximum prefix limit in Minutes + min_int: 1 + max_int: 65535 + example: 1 + exclude_example: true +# BGP - IPv4 - Neighbor - Routes + - model_name: advertisementInterval + data_path: [neighborRoutes] + tf_name: neighbor_routes_advertisement_interval + type: Int64 + description: Time interval to advertise routes in seconds + min_int: 0 + max_int: 600 + default_value: 0 + example: 1 + exclude_example: true + - model_name: removePrivateAs + data_path: [neighborRoutes] + tf_name: neighbor_routes_remove_private_as + type: Bool + description: Remove private AS numbers from outgoing routing updates + default_value: "false" + example: "false" + exclude_example: true + - model_name: id + tf_name: neighbor_generate_default_route_map_id + data_path: [neighborFiltering, neighborDefaultOriginate, routeMap] + type: String + description: Generate default routes - Route Map + exclude_test: true + exclude_example: true + - model_name: existMap + data_path: [neighborRoutes, neighborAdvertiseMaps] + tf_name: neighbor_routes_advertise_map_use_exist + type: Bool + exclude_test: true + exclude_example: true + description: Use Exist Map or Non-Exist Map + - model_name: id + tf_name: neighbor_routes_advertise_map_id + data_path: [neighborRoutes, neighborAdvertiseMaps, routeMap] + type: String + id: true + description: Specified route maps are advertised when the prefix exists in the Advertise Map and Exist Map. + exclude_test: true + exclude_example: true + - model_name: id + tf_name: neighbor_routes_advertise_exist_nonexist_map_id + data_path: [neighborRoutes, neighborAdvertiseMaps, existRouteMap] + type: String + id: true + description: Specified route maps are advertised when the prefix exists only in the Advertise Map. + exclude_test: true + exclude_example: true +# BGP - IPv4 - Neighbor - Timers + - model_name: keepAliveInterval + data_path: [neighborTimers] + tf_name: neighbor_keepalive_interval + type: Int64 + description: Time interval to send keepalive messages in seconds + min_int: 0 + max_int: 65535 + example: 60 + exclude_example: true + - model_name: holdTime + data_path: [neighborTimers] + tf_name: neighbor_hold_time + type: Int64 + description: Time interval to hold the neighbor in seconds + min_int: 3 + max_int: 65535 + example: 180 + exclude_example: true + - model_name: minimumHoldTime + data_path: [neighborTimers] + tf_name: neighbor_min_hold_time + type: Int64 + description: Minimum hold time in seconds + min_int: 3 + max_int: 65535 + example: 3 + exclude_example: true +# BGP - IPv4 - Neighbor - Advanced + - model_name: neighborSecret + tf_name: neighbor_authentication_password + data_path: [neighborAdvanced] + type: String + description: Setting password enables authentication. + exclude_example: true + exclude_test: true + - model_name: sendCommunity + tf_name: neighbor_send_community_attribute + data_path: [neighborAdvanced] + type: Bool + description: Send Community attribute to this neighbor + default_value: "false" + example: "false" + exclude_example: true + - model_name: nextHopSelf + tf_name: neighbor_nexthop_self + data_path: [neighborAdvanced] + type: Bool + exclude_example: true + default_value: "false" + example: "false" + description: Use itself as next hop for this neighbor + - model_name: disableConnectedCheck + tf_name: neighbor_disable_connection_verification + data_path: [neighborAdvanced, neighborHops] + type: Bool + description: Disable Connection Verification + exclude_example: true + default_value: "false" + example: "false" + - model_name: disable + tf_name: neighbor_tcp_mtu_path_discovery + data_path: [neighborAdvanced, neighborTransportPathMTUDiscovery] + type: Bool + description: Use TCP path MTU discovery. + default_value: "false" + example: "false" + exclude_example: true + - model_name: maxHopCount + tf_name: neighbor_max_hop_count + data_path: [neighborAdvanced, neighborHops] + type: Int64 + description: Maximum number of hops to reach the neighbor + min_int: 1 + max_int: 255 + default_value: 1 + example: 1 + exclude_example: true + - model_name: establishTCPSession + tf_name: neighbor_tcp_transport_mode + data_path: [neighborAdvanced, neighborTransportConnectionMode] + type: Bool + description: True set it to active, False to passive. + default_value: "false" + example: "false" + exclude_example: true + - model_name: neighborWeight + tf_name: neighbor_weight + data_path: [neighborAdvanced] + type: Int64 + description: Weight of the neighbor + min_int: 0 + max_int: 65535 + default_value: 0 + example: 0 + exclude_example: true + - model_name: neighborVersion + tf_name: neighbor_version + data_path: [neighborAdvanced] + type: String + enum_values: ["0", "4"] + default_value: "0" + example: "0" + exclude_example: true + description: "Set BPG version: 0 - default, 4 - IPv4" +# BGP - IPv4 - Neighbor - Migration + - model_name: asNumber + tf_name: neighbor_customized_local_as_number + data_path: [neighborLocalAs] + type: String + description: Customize the AS number for the routes received from neighbor + exclude_test: true + exclude_example: true + - model_name: noPrepend + tf_name: neighbor_customized_no_prepend + data_path: [neighborLocalAs] + type: Bool + description: Do not prepend local AS number to routes received from neighbor + exclude_test: true + exclude_example: true + - model_name: replaceAs + tf_name: neighbor_customized_replace_as + data_path: [neighborLocalAs] + type: Bool + description: Replace real AS number with local AS number in routes received from neighbor + exclude_test: true + exclude_example: true + - model_name: dualAs + tf_name: neighbor_customized_accept_both_as + data_path: [neighborLocalAs] + type: Bool + description: Accept either real AS number or local AS number in routes experienced from neighbor + exclude_test: true + exclude_example: true +# BGP - IPv4 - Aggregate Address + - model_name: aggregateAddressesIPv4s + tf_name: ipv4_aggregate_addresses + data_path: [addressFamilyIPv4] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: asSet + tf_name: generate_as + type: Bool + description: Generate AS set path information + exclude_test: true + exclude_example: true + - model_name: summaryOnly + tf_name: filter + type: Bool + description: Filter all routes from updates (summary only) + exclude_test: true + exclude_example: true + - model_name: id + tf_name: network_id + data_path: [ipv4AggregateNetwork] + type: String + description: Network ID + id: true + exclude_test: true + exclude_example: true + - model_name: id + tf_name: advertise_map_id + data_path: [advertiseMap] + type: String + description: Advertise Map ID + id: true + exclude_test: true + exclude_example: true + - model_name: id + tf_name: attribute_map_id + data_path: [attributeMap] + type: String + description: Attribute Map ID + id: true + exclude_test: true + exclude_example: true + - model_name: id + tf_name: suppress_map_id + data_path: [suppressMap] + type: String + description: Suppress Map ID + id: true + exclude_test: true + exclude_example: true +# BGP - IPv4 - Filtering + - model_name: distributeLists + tf_name: ipv4_filterings + data_path: [addressFamilyIPv4] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: access_list_id + data_path: [ipv4AggregateNetwork] + type: String + description: Standard Access List ID + id: true + exclude_test: true + exclude_example: true + - model_name: type + tf_name: network_direction + type: String + enum_values: [incomingroutefilter, outgoingroutefilter] + description: Filtering directrion + exclude_test: true + exclude_example: true + - model_name: protocol + tf_name: protocol + data_path: [protocol] + type: String + description: Protocol ## TODO: Enum values + exclude_test: true + exclude_example: true + - model_name: processId ## TODO: Enum values + tf_name: prorocol_process + data_path: [protocol] + type: String + description: Process ID + exclude_test: true + exclude_example: true +# BGP - IPv4 - Networks + - model_name: networks + tf_name: ipv4_networks + data_path: [addressFamilyIPv4] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: network_id + data_path: [ipv4Address] + type: String + description: Network object ID + id: true + exclude_test: true + exclude_example: true + - model_name: id + tf_name: route_map_id + data_path: [routeMap] + type: String + description: Route Map ID + id: true + exclude_test: true + exclude_example: true +# BGP - IPv4 - Redistribution + - model_name: redistributeProtocols + tf_name: ipv4_redistributions + data_path: [addressFamilyIPv4] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: type + tf_name: source_protocol + type: String + enum_values: [RedistributeConnected, RedistributeStatic, RedistributeOSPF, RedistributeEIGRP ] + description: Protocol to redistribute + exclude_test: true + exclude_example: true + - model_name: id + tf_name: route_map_id + data_path: [routeMap] + type: String + description: Route Map ID + id: true + exclude_test: true + exclude_example: true + - model_name: metricValue + tf_name: metric + data_path: [routeMetric] + type: Int64 + description: Metric value + min_int: 0 + max_int: 4294967295 + exclude_test: true + exclude_example: true + - model_name: processId + type: String + description: process ID + exclude_test: true + exclude_example: true + - model_name: matchExternal1 + type: Bool + description: Match OSPF External 1 metrics + exclude_test: true + exclude_example: true + - model_name: matchExternal2 + type: Bool + description: Match OSPF External 2 metrics + exclude_test: true + exclude_example: true + - model_name: matchInternal + type: Bool + description: Match OSPF Internal metrics + exclude_test: true + exclude_example: true + - model_name: matchNssaExternal1 + type: Bool + description: Match OSPF NSSA External 1 metrics + exclude_test: true + exclude_example: true + - model_name: matchNssaExternal2 + type: Bool + description: Match OSPF NSSA External 2 metrics + exclude_test: true + exclude_example: true +# BGP - IPv4 - Route Injection + - model_name: injectMaps + tf_name: ipv4_route_injections + data_path: [addressFamilyIPv4] + type: List + exclude_test: true + exclude_example: true + attributes: + - model_name: id + tf_name: inject_route_map_id + data_path: [injectMap, routeMap] + type: String + description: Inject Route Map ID + id: true + exclude_test: true + exclude_example: true + - model_name: id + tf_name: exist_route_map_id + data_path: [existMap, routeMap] + type: String + description: Exist Route Map ID + id: true + exclude_test: true + exclude_example: true + +# BGP - IPv6 - TODO + +test_prerequisites: |- + variable "device_id" { default = null } // tests will set $TF_VAR_device_id + + resource "fmc_device_bgp_general_settings" "test" { + device_id = var.device_id + as_number = "6353" + } diff --git a/gen/definitions/device_bgp_general_settings.yaml b/gen/definitions/device_bgp_general_settings.yaml new file mode 100644 index 00000000..94f470ca --- /dev/null +++ b/gen/definitions/device_bgp_general_settings.yaml @@ -0,0 +1,179 @@ +--- +name: Device BGP General Settings +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bgpgeneralsettings +doc_category: Devices +test_tags: [TF_VAR_device_id] +attributes: + - model_name: device_id + type: String + reference: true + requires_replace: true + description: UUID of the parent device (fmc_device.example.id). + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + test_value: var.device_id + - model_name: name + type: String + description: Object name; Always set to 'AsaBGPGeneralTable' + computed: true + - model_name: asNumber + type: String + description: Autonomous System (AS) number in asplain or asdot format + mandatory: true + example: "65535" + data_source_query: true + - model_name: routerId + type: String + example: AUTOMATIC + description: String value for the routerID. Possible values can be 'AUTOMATIC' or valid ipv4 address +# BGP - General + - model_name: scanTime + tf_name: scanning_interval + type: Int64 + min_int: 5 + max_int: 60 + example: 60 + description: Scanning interval of BGP routers for next hop validation in Seconds. + - model_name: maxasLimit + tf_name: as_number_in_path_attribute + type: Int64 + min_int: 1 + max_int: 254 + example: 50 + description: Range to discard routes that have as-path segments that exceed a specified value. + - model_name: logNeighborChanges + type: Bool + exclude_example: true + example: "false" + description: Enable logging of BGP neighbor status changes. + - model_name: transportPathMtuDiscovery + tf_name: tcp_path_mtu_discovery + type: Bool + example: "true" + description: Use TCP path MTU discovery. + - model_name: fastExternalFallOver + tf_name: reset_session_upon_failover + type: Bool + description: Reset session upon failover + example: "true" + - model_name: enforceFirstAs + tf_name: enforce_first_peer_as + type: Bool + description: Discard updates received from an external BGP (eBGP) peers that do not list their autonomous system (AS) number. + example: "true" + - model_name: asnotationDot + tf_name: use_dot_notation + type: Bool + example: "false" + description: Change format of BGP 4-byte autonomous system numbers from asplain (decimal values) to dot notation. + - model_name: aggregateTimer + type: Int64 + min_int: 6 + max_int: 60 + example: 30 + exclude_example: true + description: Interval at which BGP routes will be aggregated or to disable timer-based router aggregation (in seconds). +# BGP - Best Path Selection + - model_name: defaultLocalPreferenceValue + tf_name: default_local_preference + data_path: [bestPath] + type: Int64 + description: Default local preference + min_int: 0 + max_int: 4294967295 + example: 100 + exclude_example: true + - model_name: alwaysCompareMed + tf_name: compare_med_from_different_neighbors + data_path: [bestPath] + type: Bool + description: Allow comparing MED from different neighbors + example: "true" + exclude_example: true + - model_name: deterministicMed + tf_name: compare_router_id_in_path + data_path: [bestPath] + type: Bool + description: Compare Router ID for identical EBGP paths + example: "true" + exclude_example: true + - model_name: bestPathCompareRouterId + tf_name: pick_best_med + data_path: [bestPath] + type: Bool + description: Pick the best-MED path among paths advertised by neighbor AS + example: "true" + exclude_example: true + - model_name: bestPathMedMissingAsWorst + tf_name: missing_med_as_best + data_path: [bestPath] + type: Bool + description: Treat missing MED as the best preferred path + example: "false" + exclude_example: true +# BGP - Neighbor Timers + - model_name: keepAlive + tf_name: keepalive_interval + data_path: [bgptimers] + type: Int64 + description: Keepalive interval in seconds + min_int: 0 + max_int: 65535 + example: 60 + exclude_example: true + - model_name: holdTime + data_path: [bgptimers] + type: Int64 + description: Hold time in seconds + min_int: 0 + max_int: 65535 + example: 180 + exclude_example: true + - model_name: minHoldTime + data_path: [bgptimers] + type: Int64 + description: Minimum hold time (0 or 3-65535 seconds) + min_int: 0 + max_int: 65535 + example: 0 + exclude_example: true +# BGP - Next Hop + - model_name: bgpNextHopTriggerEnable + tf_name: next_hop_address_tracking + type: Bool + description: Enable next hop address tracking + exclude_example: true + exclude_test: true + - model_name: bgpNextHopTriggerDelay + tf_name: next_hop_delay_interval + type: Int64 + description: Next hop delay interval in seconds + min_int: 0 + max_int: 100 + example: 5 + exclude_example: true +# BGP - Graceful Restart (used in HA or Cluster setup) + - model_name: gracefulRestart + data_path: [bgpGracefulRestart] + type: Bool + description: Enable graceful restart + exclude_example: true + exclude_test: true + - model_name: gracefulRestartRestartTime + data_path: [bgpGracefulRestart] + type: Int64 + description: Graceful Restart Time in seconds + min_int: 1 + max_int: 3600 + exclude_example: true + exclude_test: true + - model_name: gracefulRestartStalePathTime + data_path: [bgpGracefulRestart] + type: Int64 + description: Stalepath Time in seconds + min_int: 1 + max_int: 3600 + exclude_example: true + exclude_test: true + +test_prerequisites: |- + variable "device_id" { default = null } // tests will set $TF_VAR_device_id \ No newline at end of file diff --git a/gen/definitions/device_etherchannel_interface.yaml b/gen/definitions/device_etherchannel_interface.yaml index c7b5477e..f16fa91d 100644 --- a/gen/definitions/device_etherchannel_interface.yaml +++ b/gen/definitions/device_etherchannel_interface.yaml @@ -1,7 +1,6 @@ --- name: Device EtherChannel Interface rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/etherchannelinterfaces -data_source_name_query: true doc_category: Devices test_tags: [TF_VAR_device_id, TF_VAR_interface_id, FMC_DEVICE_ETHERCHANNEL_INTERFACE] attributes: @@ -69,6 +68,7 @@ attributes: type: String description: Name of the interface; it must already be present on the device. computed: true + data_source_query: true - model_name: MTU tf_name: mtu type: Int64 diff --git a/gen/definitions/device_ha_pair_monitoring.yaml b/gen/definitions/device_ha_pair_monitoring.yaml new file mode 100644 index 00000000..bd77f9d9 --- /dev/null +++ b/gen/definitions/device_ha_pair_monitoring.yaml @@ -0,0 +1,70 @@ +--- +name: Device HA Pair Monitoring +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs/%v/monitoredinterfaces +put_create: true +doc_category: Device +test_tags: [TF_VAR_device_ha_id] +attributes: + - tf_name: device_id + type: String + reference: true + description: UUID of the parent HA device (fmc_device.example.id). + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + test_value: var.device_ha_id + - model_name: type + type: String + computed: true + description: Type of the resource. +# General + - model_name: name + tf_name: logical_name + description: Logical Name of the monitored interface. + mandatory: true + type: String + example: "outside" + data_source_query: true + - model_name: monitorForFailures + tf_name: monitor_interface + description: Monitor this interface for failures. + mandatory: true + type: Bool + example: true + - model_name: activeIPv4Address + tf_name: ipv4_active_address + data_path: [ipv4Configuration] + type: String + description: >- + Active IPv4 address from the interface. + computed: true + - model_name: standbyIPv4Address + tf_name: ipv4_standby_address + data_path: [ipv4Configuration] + type: String + description: >- + Standby IPv4 address. It has to be in the same subnet as primaty IP configured on this interface. + example: 10.1.1.2 + - model_name: activeIPv4Mask + tf_name: ipv4_netmask + data_path: [ipv4Configuration] + type: String + description: >- + IPv4 Network Mask assigned on the interface. + computed: true + - model_name: ipv6ActiveStandbyPair + data_path: [ipv6Configuration] + tf_name: ipv6_addresses + type: List + attributes: + - model_name: activeIPv6 + tf_name: active_address + type: String + description: Active IPv6 address with prefix. Address has to be configured on the interface. + example: "2006::1/30" + - model_name: standbyIPv6 + tf_name: standby_address + type: String + description: Standby IPv6 address. Address has to be from the same subnet as active IPv6 address. + example: "2006::2" + +test_prerequisites: |- + variable "device_ha_id" { default = null } // tests will set $TF_VAR_device_ha_id diff --git a/gen/definitions/device_physical_interface.yaml b/gen/definitions/device_physical_interface.yaml index 8623ba8d..5d149797 100644 --- a/gen/definitions/device_physical_interface.yaml +++ b/gen/definitions/device_physical_interface.yaml @@ -2,7 +2,6 @@ name: Device Physical Interface rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/physicalinterfaces put_create: true -data_source_name_query: true doc_category: Devices test_tags: [TF_VAR_device_id] attributes: @@ -73,6 +72,7 @@ attributes: description: Name of the interface; it must already be present on the device. mandatory: true example: GigabitEthernet0/1 + data_source_query: true - model_name: MTU tf_name: mtu type: Int64 diff --git a/gen/definitions/device_subinterface.yaml b/gen/definitions/device_subinterface.yaml index f8a4a9b1..982f45be 100644 --- a/gen/definitions/device_subinterface.yaml +++ b/gen/definitions/device_subinterface.yaml @@ -2,7 +2,6 @@ name: Device Subinterface rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/subinterfaces doc_category: Devices -data_source_name_query: true test_tags: [TF_VAR_device_id, TF_VAR_interface_name] attributes: - tf_name: device_id @@ -20,6 +19,7 @@ attributes: type: String computed: true description: Name of the subinterface in format `interface_name.subinterface_id` (eg. GigabitEthernet0/1.7). + data_source_query: true # General - model_name: ifname tf_name: logical_name diff --git a/gen/definitions/device_vrf.yaml b/gen/definitions/device_vrf.yaml index d55c5708..633b6c18 100644 --- a/gen/definitions/device_vrf.yaml +++ b/gen/definitions/device_vrf.yaml @@ -1,7 +1,6 @@ --- name: Device VRF rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/virtualrouters -data_source_name_query: true doc_category: Devices test_tags: [TF_VAR_device_id, TF_VAR_interface_name] attributes: @@ -18,6 +17,7 @@ attributes: requires_replace: true description: The name of the VRF example: VRF_A + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'VirtualRouter'. diff --git a/gen/definitions/device_vtep_policy.yaml b/gen/definitions/device_vtep_policy.yaml index 12937f23..00700a81 100644 --- a/gen/definitions/device_vtep_policy.yaml +++ b/gen/definitions/device_vtep_policy.yaml @@ -12,7 +12,6 @@ attributes: - tf_name: device_id type: String reference: true - requires_replace: true description: >- UUID of the parent device (fmc_device.example.id). example: 76d24097-41c4-4558-a4d0-a8c07ac08470 @@ -61,7 +60,6 @@ attributes: description: Encapsulation type. enum_values: [VXLAN, GENEVE] default_value: VXLAN - requires_replace: true exclude_example: true exclude_test: true - model_name: nveNeighborDiscoveryType diff --git a/gen/definitions/dynamic_objects.yaml b/gen/definitions/dynamic_objects.yaml index e45a7dd8..7cf22075 100644 --- a/gen/definitions/dynamic_objects.yaml +++ b/gen/definitions/dynamic_objects.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_dynamic_objects` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.0" attributes: - model_name: items diff --git a/gen/definitions/extended_acl.yaml b/gen/definitions/extended_acl.yaml index 9bb939cb..00f7c2ca 100644 --- a/gen/definitions/extended_acl.yaml +++ b/gen/definitions/extended_acl.yaml @@ -1,7 +1,6 @@ --- name: Extended ACL rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/extendedaccesslists -data_source_name_query: true doc_category: Objects minimum_version_create: "7.2" attributes: @@ -10,6 +9,7 @@ attributes: description: User-created name of the resource. mandatory: true example: extended_acl_1 + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/file_policy.yaml b/gen/definitions/file_policy.yaml index bb73b5a6..63b515dd 100644 --- a/gen/definitions/file_policy.yaml +++ b/gen/definitions/file_policy.yaml @@ -1,7 +1,6 @@ --- name: File Policy rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/filepolicies -data_source_name_query: true doc_category: Policy attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: mandatory: true description: The name of file policy. example: file_policy_1 + data_source_query: true - model_name: type type: String description: Type of the object diff --git a/gen/definitions/fqdn_object.yaml b/gen/definitions/fqdn_object.yaml index 571c846c..87c028f9 100644 --- a/gen/definitions/fqdn_object.yaml +++ b/gen/definitions/fqdn_object.yaml @@ -1,7 +1,6 @@ --- name: FQDN Object rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/fqdns -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the resource. mandatory: true example: fqdn_1 + data_source_query: true - model_name: value type: String description: The fully qualified domain name. diff --git a/gen/definitions/fqdn_objects.yaml b/gen/definitions/fqdn_objects.yaml index bde468e9..17e05880 100644 --- a/gen/definitions/fqdn_objects.yaml +++ b/gen/definitions/fqdn_objects.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_fqdn_objecs` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items diff --git a/gen/definitions/ftd_nat_policy.yaml b/gen/definitions/ftd_nat_policy.yaml index 4fa7c7ab..f05e1fc4 100644 --- a/gen/definitions/ftd_nat_policy.yaml +++ b/gen/definitions/ftd_nat_policy.yaml @@ -1,7 +1,6 @@ --- name: FTD NAT Policy rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/ftdnatpolicies -data_source_name_query: true doc_category: Policy attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: mandatory: true description: The name of the FTD Network Address Translation (NAT) policy. example: nat_policy_1 + data_source_query: true - model_name: description type: String description: Policy description diff --git a/gen/definitions/host.yaml b/gen/definitions/host.yaml index 63e7eab5..79b05de2 100644 --- a/gen/definitions/host.yaml +++ b/gen/definitions/host.yaml @@ -1,7 +1,6 @@ --- name: Host rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/hosts -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: mandatory: true description: The name of the host object. example: HOST1 + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'Host'. diff --git a/gen/definitions/hosts.yaml b/gen/definitions/hosts.yaml index bcdc6a3d..eb10b7bb 100644 --- a/gen/definitions/hosts.yaml +++ b/gen/definitions/hosts.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_hosts` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items diff --git a/gen/definitions/icmpv4_object.yaml b/gen/definitions/icmpv4_object.yaml index 1ca7020d..5443e4aa 100644 --- a/gen/definitions/icmpv4_object.yaml +++ b/gen/definitions/icmpv4_object.yaml @@ -1,7 +1,6 @@ --- name: ICMPv4 Object rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/icmpv4objects -data_source_name_query: true doc_category: Objects attributes: - model_name: icmpType @@ -23,6 +22,7 @@ attributes: description: User-created name of the resource. mandatory: true example: icmpv4_net_unreachable + data_source_query: true - model_name: description type: String description: Optional description of the resource. diff --git a/gen/definitions/icmpv4_objects.yaml b/gen/definitions/icmpv4_objects.yaml index 19d44c8f..fd3e6d5a 100644 --- a/gen/definitions/icmpv4_objects.yaml +++ b/gen/definitions/icmpv4_objects.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_icmpv4_objects` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items diff --git a/gen/definitions/icmpv6_object.yaml b/gen/definitions/icmpv6_object.yaml index e89232cb..dad8aa2c 100644 --- a/gen/definitions/icmpv6_object.yaml +++ b/gen/definitions/icmpv6_object.yaml @@ -1,7 +1,6 @@ --- name: ICMPv6 Object rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/icmpv6objects -data_source_name_query: true doc_category: Objects attributes: - model_name: icmpType @@ -23,6 +22,7 @@ attributes: description: User-created name of the resource. mandatory: true example: icmpv6_addr_unreachable + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/interface_group.yaml b/gen/definitions/interface_group.yaml index e590780f..2b7487c9 100644 --- a/gen/definitions/interface_group.yaml +++ b/gen/definitions/interface_group.yaml @@ -1,7 +1,6 @@ --- name: Interface Group rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/interfacegroups -data_source_name_query: true doc_category: Objects test_tags: [TF_VAR_device_id] attributes: @@ -10,6 +9,7 @@ attributes: description: User-created name of the object. mandatory: true example: interface_group_1 + data_source_query: true - model_name: interfaceMode type: String description: All interfaces' types must match the interface mode. diff --git a/gen/definitions/intrusion_policy.yaml b/gen/definitions/intrusion_policy.yaml index 52486419..e0f36264 100644 --- a/gen/definitions/intrusion_policy.yaml +++ b/gen/definitions/intrusion_policy.yaml @@ -1,7 +1,6 @@ --- name: Intrusion Policy rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/intrusionpolicies -data_source_name_query: true doc_category: Policy attributes: - model_name: name @@ -11,6 +10,7 @@ attributes: or 'Security Over Connectivity'. mandatory: true example: ips_policy_1 + data_source_query: true - model_name: description type: String description: Optional description of the policy. diff --git a/gen/definitions/network.yaml b/gen/definitions/network.yaml index 9eeadec8..6063da76 100644 --- a/gen/definitions/network.yaml +++ b/gen/definitions/network.yaml @@ -1,7 +1,6 @@ --- name: Network rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/networks -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,11 +8,11 @@ attributes: mandatory: true description: The name of the network object. example: NET1 + data_source_query: true - model_name: type type: String - description: Type of the object; this value is always 'Network'. - default_value: Network - requires_replace: true + description: "Type of the object; this value is always 'Network'." + computed: true exclude_example: true exclude_test: true - model_name: description diff --git a/gen/definitions/network_analysis_policy.yaml b/gen/definitions/network_analysis_policy.yaml index 5b57cb2c..c4f5af1d 100644 --- a/gen/definitions/network_analysis_policy.yaml +++ b/gen/definitions/network_analysis_policy.yaml @@ -1,7 +1,6 @@ --- name: Network Analysis Policy rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/networkanalysispolicies -data_source_name_query: true doc_category: Policy attributes: - model_name: name @@ -11,6 +10,7 @@ attributes: or 'Security Over Connectivity'. mandatory: true example: net_analysis_policy_1 + data_source_query: true - model_name: description type: String description: Optional description of the policy. diff --git a/gen/definitions/networks.yaml b/gen/definitions/networks.yaml index aa7a65a9..d33a53ff 100644 --- a/gen/definitions/networks.yaml +++ b/gen/definitions/networks.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_networks` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items @@ -43,6 +41,6 @@ attributes: - model_name: type type: String description: Type of the object; this value is always 'Network'. - default_value: Network + computed: true exclude_example: true exclude_test: true \ No newline at end of file diff --git a/gen/definitions/port.yaml b/gen/definitions/port.yaml index 03cc531c..817d0d49 100644 --- a/gen/definitions/port.yaml +++ b/gen/definitions/port.yaml @@ -1,7 +1,6 @@ --- name: Port rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/protocolportobjects -data_source_name_query: true doc_category: Objects attributes: - model_name: port @@ -14,6 +13,7 @@ attributes: description: User-created name of the resource. mandatory: true example: tcp443 + data_source_query: true - model_name: protocol type: String description: >- diff --git a/gen/definitions/port_group.yaml b/gen/definitions/port_group.yaml index e15928b3..70c91ade 100644 --- a/gen/definitions/port_group.yaml +++ b/gen/definitions/port_group.yaml @@ -1,7 +1,6 @@ --- name: Port Group rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/portobjectgroups -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,11 +8,11 @@ attributes: description: User-created name of the object. mandatory: true example: portgroup_obj1 + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'PortObjectGroup'. - default_value: PortObjectGroup - requires_replace: true + computed: true exclude_example: true exclude_test: true - model_name: description diff --git a/gen/definitions/port_groups.yaml b/gen/definitions/port_groups.yaml index e0fbc061..f4aca4e5 100644 --- a/gen/definitions/port_groups.yaml +++ b/gen/definitions/port_groups.yaml @@ -6,8 +6,6 @@ res_description: >- The FMC API supports quick bulk creation for this resource, but the deletion/modification is done one-by-one. Updating and deleting `fmc_port_groups` can thus take much more time than creating it (even >500 times more time, i.e. >50000%, depending on the change size). -data_source_name_query: true -import_name_query: yes is_bulk: true doc_category: Objects minimum_version_bulk_delete: "7.4" @@ -28,8 +26,7 @@ attributes: - model_name: type type: String description: Type of the object; this value is always 'PortObjectGroup'. - default_value: PortObjectGroup - requires_replace: true + computed: true exclude_example: true exclude_test: true - model_name: description diff --git a/gen/definitions/ports.yaml b/gen/definitions/ports.yaml index 8b7d1563..2eb1fd51 100644 --- a/gen/definitions/ports.yaml +++ b/gen/definitions/ports.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_ports` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items diff --git a/gen/definitions/range.yaml b/gen/definitions/range.yaml index f117711a..c5c2321e 100644 --- a/gen/definitions/range.yaml +++ b/gen/definitions/range.yaml @@ -1,7 +1,6 @@ --- name: Range rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/ranges -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the resource. mandatory: true example: range1 + data_source_query: true - model_name: value tf_name: ip_range type: String diff --git a/gen/definitions/ranges.yaml b/gen/definitions/ranges.yaml index 8d475049..54d927ea 100644 --- a/gen/definitions/ranges.yaml +++ b/gen/definitions/ranges.yaml @@ -7,8 +7,6 @@ res_description: >- Updating/deleting `fmc_ranges` can thus take much more time than creating it doc_category: Objects is_bulk: true -data_source_name_query: yes -import_name_query: yes minimum_version_bulk_delete: "7.4" attributes: - model_name: items diff --git a/gen/definitions/security_zone.yaml b/gen/definitions/security_zone.yaml index 25206fb4..da221355 100644 --- a/gen/definitions/security_zone.yaml +++ b/gen/definitions/security_zone.yaml @@ -2,14 +2,15 @@ name: Security Zone rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/securityzones doc_category: Objects -data_source_name_query: true attributes: - model_name: name type: String mandatory: true description: User-provided resource name. example: security_zone_1 + data_source_query: true - model_name: interfaceMode + tf_name: interface_type type: String mandatory: true description: >- @@ -17,10 +18,9 @@ attributes: to mode NONE of associated interfaces. enum_values: [PASSIVE, INLINE, SWITCHED, ROUTED, ASA] example: ROUTED - requires_replace: true - model_name: type type: String description: Type of the object; this value is always 'SecurityZone'. - default_value: SecurityZone + computed: true exclude_example: true exclude_test: true \ No newline at end of file diff --git a/gen/definitions/security_zones.yaml b/gen/definitions/security_zones.yaml index 14217ea6..e0d9c9f5 100644 --- a/gen/definitions/security_zones.yaml +++ b/gen/definitions/security_zones.yaml @@ -2,8 +2,6 @@ name: Security Zones rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/securityzones is_bulk: true -data_source_name_query: true -import_name_query: yes res_description: >- This plural resource manages a bulk of Security Zones. The FMC API supports quick bulk creation of this resource. Deletion of this resource is done one-by-one or in bulk, depending of FMC version. Modification is always done one-by-one. @@ -26,6 +24,7 @@ attributes: exclude_example: true exclude_test: true - model_name: interfaceMode + tf_name: interface_type type: String mandatory: true description: >- @@ -33,10 +32,9 @@ attributes: to mode NONE of associated interfaces. enum_values: [PASSIVE, INLINE, SWITCHED, ROUTED, ASA] example: ROUTED - requires_replace: true - model_name: type type: String description: Type of the object; this value is always 'SecurityZone'. - default_value: SecurityZone + computed: true exclude_example: true exclude_test: true \ No newline at end of file diff --git a/gen/definitions/sgt.yaml b/gen/definitions/sgt.yaml index f3181852..121394ea 100644 --- a/gen/definitions/sgt.yaml +++ b/gen/definitions/sgt.yaml @@ -1,7 +1,6 @@ --- name: SGT rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/securitygrouptags -data_source_name_query: true doc_category: Objects minimum_version_create: "7.4" attributes: @@ -10,6 +9,7 @@ attributes: mandatory: true description: The name of the SGT object. example: SGT1 + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'SecurityGroupTag'. diff --git a/gen/definitions/sgts.yaml b/gen/definitions/sgts.yaml index 6aa85102..1d8ab4bb 100644 --- a/gen/definitions/sgts.yaml +++ b/gen/definitions/sgts.yaml @@ -1,10 +1,8 @@ --- name: SGTs rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/securitygrouptags -data_source_name_query: true is_bulk: true doc_category: Objects -import_name_query: yes minimum_version_create: "7.4" minimum_version_bulk_create: "999" minimum_version_bulk_delete: "999" diff --git a/gen/definitions/snmp_alert.yaml b/gen/definitions/snmp_alert.yaml index 98255921..379f9b37 100644 --- a/gen/definitions/snmp_alert.yaml +++ b/gen/definitions/snmp_alert.yaml @@ -1,7 +1,6 @@ --- name: SNMP Alert rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/snmpalerts -data_source_name_query: true no_resource: true no_import: true doc_category: Policy @@ -12,10 +11,10 @@ attributes: Name of the SNMP Alert. There is no built-in SNMP alert. mandatory: true example: test_snmp_alert_1 + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'SNMPAlert'. - default_value: SNMPAlert - requires_replace: true + computed: true exclude_example: true exclude_test: true diff --git a/gen/definitions/snmp_alerts.yaml b/gen/definitions/snmp_alerts.yaml index b1fd1357..1b1fb390 100644 --- a/gen/definitions/snmp_alerts.yaml +++ b/gen/definitions/snmp_alerts.yaml @@ -1,8 +1,6 @@ --- name: SNMP Alerts rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/snmpalerts -data_source_name_query: true -import_name_query: true no_resource: true no_import: true is_bulk: true @@ -24,7 +22,6 @@ attributes: - model_name: type type: String description: Type of the object; this value is always 'SNMPAlert'. - default_value: SNMPAlert - requires_replace: true + computed: true exclude_example: true exclude_test: true diff --git a/gen/definitions/standard_acl.yaml b/gen/definitions/standard_acl.yaml index b4d24593..da5c33b2 100644 --- a/gen/definitions/standard_acl.yaml +++ b/gen/definitions/standard_acl.yaml @@ -1,7 +1,6 @@ --- name: Standard ACL rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/standardaccesslists -data_source_name_query: true doc_category: Objects minimum_version_create: "7.2" attributes: @@ -10,6 +9,7 @@ attributes: description: User-created name of the resource. mandatory: true example: stdacl1 + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/syslog_alert.yaml b/gen/definitions/syslog_alert.yaml index 62ac9240..51aa7d35 100644 --- a/gen/definitions/syslog_alert.yaml +++ b/gen/definitions/syslog_alert.yaml @@ -1,7 +1,6 @@ --- name: Syslog Alert rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/syslogalerts -data_source_name_query: true no_resource: true no_import: true doc_category: Policy @@ -12,10 +11,10 @@ attributes: Name of the Syslog Alert. There is no built-in Syslog alert. mandatory: true example: test_syslog_alert_1 + data_source_query: true - model_name: type type: String description: Type of the object; this value is always 'SyslogAlert'. - default_value: SyslogAlert - requires_replace: true + computed: true exclude_example: true exclude_test: true diff --git a/gen/definitions/syslog_alerts.yaml b/gen/definitions/syslog_alerts.yaml index daeb4dcb..9724a278 100644 --- a/gen/definitions/syslog_alerts.yaml +++ b/gen/definitions/syslog_alerts.yaml @@ -1,8 +1,6 @@ --- name: Syslog Alerts rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/policy/syslogalerts -data_source_name_query: true -import_name_query: true no_resource: true no_import: true is_bulk: true @@ -24,7 +22,6 @@ attributes: - model_name: type type: String description: Type of the object; this value is always 'SyslogAlert'. - default_value: SyslogAlert - requires_replace: true + computed: true exclude_example: true exclude_test: true diff --git a/gen/definitions/url.yaml b/gen/definitions/url.yaml index b54b49f1..ae0ba1ec 100644 --- a/gen/definitions/url.yaml +++ b/gen/definitions/url.yaml @@ -1,7 +1,6 @@ --- name: URL rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/urls -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the resource. mandatory: true example: url_1 + data_source_query: true - model_name: url type: String description: URL value. diff --git a/gen/definitions/url_group.yaml b/gen/definitions/url_group.yaml index 146e0bed..c69e7482 100644 --- a/gen/definitions/url_group.yaml +++ b/gen/definitions/url_group.yaml @@ -1,7 +1,6 @@ --- name: URL Group rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/urlgroups -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the object. mandatory: true example: url_group_1 + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/url_groups.yaml b/gen/definitions/url_groups.yaml index b1dbf824..19780039 100644 --- a/gen/definitions/url_groups.yaml +++ b/gen/definitions/url_groups.yaml @@ -6,8 +6,6 @@ res_description: >- The FMC API supports quick bulk creation for this resource, but the deletion/modification is done one-by-one. Updating and deleting `fmc_url_groups` can thus take much more time than creating it (even >500 times more time, i.e. >50000%, depending on the change size). -data_source_name_query: true -import_name_query: yes is_bulk: true doc_category: Objects minimum_version_bulk_delete: "7.4" diff --git a/gen/definitions/urls.yaml b/gen/definitions/urls.yaml index ff5045f1..40b110fe 100644 --- a/gen/definitions/urls.yaml +++ b/gen/definitions/urls.yaml @@ -2,8 +2,6 @@ name: URLs rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/urls is_bulk: true -data_source_name_query: true -import_name_query: yes res_description: >- This plural resource manages a bulk of URL objects. The FMC API supports quick bulk creation of this resource. Deletion of this resource is done one-by-one or in bulk, depending of FMC version. Modification is always done one-by-one. diff --git a/gen/definitions/variable_set.yaml b/gen/definitions/variable_set.yaml index 0afc7f78..83cfdafd 100644 --- a/gen/definitions/variable_set.yaml +++ b/gen/definitions/variable_set.yaml @@ -1,7 +1,6 @@ --- name: Variable Set rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/variablesets -data_source_name_query: true no_resource: true no_import: true doc_category: Objects @@ -12,6 +11,7 @@ attributes: Name of the Variable Set. Names for built-in set is 'Default-Set'. mandatory: true example: test_variable_set_1 + data_source_query: true - model_name: description type: String description: Optional description of the policy. @@ -19,7 +19,6 @@ attributes: - model_name: type type: String description: Type of the object; this value is always 'VariableSet'. - default_value: VariableSet - requires_replace: true + computed: true exclude_example: true exclude_test: true diff --git a/gen/definitions/vlan_tag.yaml b/gen/definitions/vlan_tag.yaml index a4f9636f..d5a7f0a3 100644 --- a/gen/definitions/vlan_tag.yaml +++ b/gen/definitions/vlan_tag.yaml @@ -1,7 +1,6 @@ --- name: VLAN Tag rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/vlantags -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the resource. mandatory: true example: vlan_tag_1 + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/vlan_tag_group.yaml b/gen/definitions/vlan_tag_group.yaml index 4a762e7b..26aa1f93 100644 --- a/gen/definitions/vlan_tag_group.yaml +++ b/gen/definitions/vlan_tag_group.yaml @@ -1,7 +1,6 @@ --- name: VLAN Tag Group rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/vlangrouptags -data_source_name_query: true doc_category: Objects attributes: - model_name: name @@ -9,6 +8,7 @@ attributes: description: User-created name of the object. mandatory: true example: vlan_tag_group_1 + data_source_query: true - model_name: description type: String description: Optional user-created description. diff --git a/gen/definitions/vlan_tag_groups.yaml b/gen/definitions/vlan_tag_groups.yaml index 43a4b450..e3e3e3e1 100644 --- a/gen/definitions/vlan_tag_groups.yaml +++ b/gen/definitions/vlan_tag_groups.yaml @@ -6,8 +6,6 @@ res_description: >- The FMC API supports quick bulk creation for this resource, but the deletion/modification is done one-by-one. Updating and deleting `fmc_vlan_tag_groups` can thus take much more time than creating it (even >500 times more time, i.e. >50000%, depending on the change size). -data_source_name_query: true -import_name_query: yes is_bulk: true doc_category: Objects minimum_version_bulk_delete: "7.4" diff --git a/gen/definitions/vlan_tags.yaml b/gen/definitions/vlan_tags.yaml index 78b52a67..d2714937 100644 --- a/gen/definitions/vlan_tags.yaml +++ b/gen/definitions/vlan_tags.yaml @@ -2,8 +2,6 @@ name: VLAN Tags rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/object/vlantags is_bulk: true -data_source_name_query: true -import_name_query: yes res_description: >- This plural resource manages a bulk of VLAN tags. The FMC API supports quick bulk creation of this resource. Deletion of this resource is done one-by-one or in bulk, depending of FMC version. Modification is always done one-by-one. diff --git a/gen/generator.go b/gen/generator.go index d3666f3c..c7abf2ab 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -103,7 +103,6 @@ type YamlConfig struct { PutCreate bool `yaml:"put_create"` NoUpdate bool `yaml:"no_update"` NoDelete bool `yaml:"no_delete"` - DataSourceNameQuery bool `yaml:"data_source_name_query"` MinimumVersion string `yaml:"minimum_version"` MinimumVersionCreate string `yaml:"minimum_version_create"` MinimumVersionBulkCreate string `yaml:"minimum_version_bulk_create"` @@ -155,6 +154,7 @@ type YamlConfigAttribute struct { TestValue string `yaml:"test_value"` MinimumTestValue string `yaml:"minimum_test_value"` TestTags []string `yaml:"test_tags"` + DataSourceQuery bool `yaml:"data_source_query"` Attributes []YamlConfigAttribute `yaml:"attributes"` GoTypeName string } @@ -217,6 +217,26 @@ func contains(s []string, str string) bool { return false } +// Templating helper function to check if any of the attributes is a data source query +func HasDataSourceQuery(attributes []YamlConfigAttribute) bool { + for _, attr := range attributes { + if attr.DataSourceQuery { + return true + } + } + return false +} + +// Templating helper function to return Data Source Query Attribute +func GetDataSourceQueryAttribute(config YamlConfig) YamlConfigAttribute { + for _, attr := range config.Attributes { + if attr.DataSourceQuery { + return attr + } + } + return YamlConfigAttribute{} +} + // Templating helper function to return true if id included in attributes func HasId(attributes []YamlConfigAttribute) bool { for _, attr := range attributes { @@ -352,28 +372,30 @@ func Subtract(a, b int) int { // Map of templating functions var functions = template.FuncMap{ - "toGoName": ToGoName, - "camelCase": CamelCase, - "snakeCase": SnakeCase, - "sprintf": fmt.Sprintf, - "errorf": Errorf, - "toLower": strings.ToLower, - "path": BuildPath, - "hasId": HasId, - "hasReference": HasReference, - "hasResourceId": HasResourceId, - "isListSet": IsListSet, - "isList": IsList, - "isSet": IsSet, - "isStringListSet": IsStringListSet, - "isInt64ListSet": IsInt64ListSet, - "isNestedListMapSet": IsNestedListMapSet, - "isNestedListSet": IsNestedListSet, - "isNestedList": IsNestedList, - "isNestedMap": IsNestedMap, - "isNestedSet": IsNestedSet, - "importParts": ImportParts, - "subtract": Subtract, + "toGoName": ToGoName, + "camelCase": CamelCase, + "snakeCase": SnakeCase, + "sprintf": fmt.Sprintf, + "errorf": Errorf, + "toLower": strings.ToLower, + "path": BuildPath, + "hasDataSourceQuery": HasDataSourceQuery, + "getDataSourceQueryAttribute": GetDataSourceQueryAttribute, + "hasId": HasId, + "hasReference": HasReference, + "hasResourceId": HasResourceId, + "isListSet": IsListSet, + "isList": IsList, + "isSet": IsSet, + "isStringListSet": IsStringListSet, + "isInt64ListSet": IsInt64ListSet, + "isNestedListMapSet": IsNestedListMapSet, + "isNestedListSet": IsNestedListSet, + "isNestedList": IsNestedList, + "isNestedMap": IsNestedMap, + "isNestedSet": IsNestedSet, + "importParts": ImportParts, + "subtract": Subtract, } func (attr *YamlConfigAttribute) init(parentGoTypeName string) error { @@ -435,6 +457,7 @@ func (attr *YamlConfigAttribute) init(parentGoTypeName string) error { func NewYamlConfig(bytes []byte) (YamlConfig, error) { var config YamlConfig + var hasDataSourceQuery bool = false if err := yaml.Unmarshal(bytes, &config); err != nil { return config, err @@ -444,6 +467,12 @@ func NewYamlConfig(bytes []byte) (YamlConfig, error) { if err := config.Attributes[i].init(CamelCase(config.Name)); err != nil { return YamlConfig{}, err } + if config.Attributes[i].DataSourceQuery { + if hasDataSourceQuery { + return YamlConfig{}, fmt.Errorf("Multiple `data_source_query` attributes found. Only one is allowed.") + } + hasDataSourceQuery = true + } } if config.DsDescription == "" { config.DsDescription = fmt.Sprintf("This data source can read the %s.", config.Name) diff --git a/gen/schema/schema.yaml b/gen/schema/schema.yaml index 039b0e80..4000a4b9 100644 --- a/gen/schema/schema.yaml +++ b/gen/schema/schema.yaml @@ -7,7 +7,6 @@ rest_endpoint: str(required=False) # REST endpoint path put_create: bool(required=False) # Set to true if the PUT request is used for create no_update: bool(required=False) # Set to true if the PUT request is not supported no_delete: bool(required=False) # Set to true if the DELETE request is not supported -data_source_name_query: bool(required=False) # Set to true if the data source supports name queries minimum_version: str(required=False) # Define a minimum supported version minimum_version_create: str(required=False) # Define a minimum version that supports create (in case it's higher than `minimum_version`) minimum_version_bulk_create: str(required=False) # Define a minimum version that supports bulk create (in case it's higher than `minimum_version`). Please use version "999" if not supported (fallback to one-by-one create) @@ -57,5 +56,6 @@ attribute: test_value: str(required=False) # Value used for acceptance test minimum_test_value: str(required=False) # Value used for "minimum" resource acceptance test test_tags: list(str(), required=False) # List of test tags, attribute is only included in acceptance tests if an environment variable with one of these tags is configured + data_source_query: bool(required=False) # Set to true if the attribute can be used in the data source query. This is supported only for top-level attributes. attributes: list(include('attribute'), required=False) # List of attributes, only relevant if type is "List" or "Set" \ No newline at end of file diff --git a/gen/templates/data_source.go b/gen/templates/data_source.go index 620b340f..67ba745e 100644 --- a/gen/templates/data_source.go +++ b/gen/templates/data_source.go @@ -56,8 +56,6 @@ func (d *{{camelCase .Name}}DataSource) Metadata(_ context.Context, req datasour resp.TypeName = req.ProviderTypeName + "_{{snakeCase .Name}}" } -{{- $nameQuery := .DataSourceNameQuery}} - func (d *{{camelCase .Name}}DataSource) 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. @@ -66,7 +64,7 @@ func (d *{{camelCase .Name}}DataSource) Schema(ctx context.Context, req datasour Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ MarkdownDescription: "The id of the object", - {{- if not .DataSourceNameQuery}} + {{- if and (not (hasDataSourceQuery .Attributes)) (not .IsBulk) }} Required: true, {{- else}} {{- if not .IsBulk}} @@ -89,7 +87,7 @@ func (d *{{camelCase .Name}}DataSource) Schema(ctx context.Context, req datasour {{- if .Reference}} Required: true, {{- else}} - {{- if and (eq .ModelName "name") ($nameQuery)}} + {{- if .DataSourceQuery }} Optional: true, {{- end}} {{- if isNestedMap .}} @@ -159,13 +157,13 @@ func (d *{{camelCase .Name}}DataSource) Schema(ctx context.Context, req datasour }, } } - -{{- if and .DataSourceNameQuery (not .IsBulk)}} +{{- $dataSourceAttribute := getDataSourceQueryAttribute .}} +{{- if and (hasDataSourceQuery .Attributes) (not .IsBulk)}} func (d *{{camelCase .Name}}DataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { return []datasource.ConfigValidator{ datasourcevalidator.ExactlyOneOf( path.MatchRoot("id"), - path.MatchRoot("name"), + path.MatchRoot("{{$dataSourceAttribute.TfName}}"), ), } } @@ -211,12 +209,12 @@ func (d *{{camelCase .Name}}DataSource) Read(ctx context.Context, req datasource tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) - {{- if and .DataSourceNameQuery (not .IsBulk)}} - if config.Id.IsNull() && !config.Name.IsNull() { + {{- if and (hasDataSourceQuery .Attributes) (not .IsBulk)}} + if config.Id.IsNull() && !config.{{toGoName $dataSourceAttribute.TfName}}.IsNull() { offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath() + queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) @@ -224,9 +222,9 @@ func (d *{{camelCase .Name}}DataSource) Read(ctx context.Context, req datasource } if value := res.Get("items"); len(value.Array()) > 0 { value.ForEach(func(k, v gjson.Result) bool { - if config.Name.ValueString() == v.Get("name").String() { + if config.{{toGoName $dataSourceAttribute.TfName}}.ValueString() == v.Get("{{$dataSourceAttribute.ModelName}}").String() { config.Id = types.StringValue(v.Get("id").String()) - tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String())) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with {{$dataSourceAttribute.TfName}} '%v', id: %v", config.Id.String(), config.{{toGoName $dataSourceAttribute.TfName}}.ValueString(), config.Id.String())) return false } return true @@ -239,7 +237,7 @@ func (d *{{camelCase .Name}}DataSource) Read(ctx context.Context, req datasource } if config.Id.IsNull() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString())) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with {{$dataSourceAttribute.TfName}}: %s", config.{{toGoName $dataSourceAttribute.TfName}}.ValueString())) return } } diff --git a/gen/templates/data_source_test.go b/gen/templates/data_source_test.go index 852d9164..5f33e37a 100644 --- a/gen/templates/data_source_test.go +++ b/gen/templates/data_source_test.go @@ -146,7 +146,7 @@ func TestAccDataSourceFmc{{camelCase .Name}}(t *testing.T) { Config: {{if .TestPrerequisites}}testAccDataSourceFmc{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccDataSourceFmc{{camelCase .Name}}Config(), Check: resource.ComposeTestCheckFunc(checks...), }, - {{- if and .DataSourceNameQuery (not .IsBulk)}} + {{- if and (hasDataSourceQuery .Attributes) (not .IsBulk)}} { Config: {{if .TestPrerequisites}}testAccDataSourceFmc{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccNamedDataSourceFmc{{camelCase .Name}}Config(), Check: resource.ComposeTestCheckFunc(checks...), @@ -288,7 +288,7 @@ func testAccDataSourceFmc{{camelCase .Name}}Config() string { return config } -{{if and .DataSourceNameQuery (not .IsBulk) -}} +{{if and (hasDataSourceQuery .Attributes) (not .IsBulk) -}} func testAccNamedDataSourceFmc{{camelCase .Name}}Config() string { config := `resource "fmc_{{snakeCase $name}}" "test" {` + "\n" {{- range .Attributes}} @@ -376,12 +376,16 @@ func testAccNamedDataSourceFmc{{camelCase .Name}}Config() string { config += ` data "fmc_{{snakeCase .Name}}" "test" { - name = fmc_{{snakeCase $name}}.test.name {{- range .Attributes}} {{- if .Reference}} {{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}} {{- end}} {{- end}} + {{- range .Attributes}} + {{- if .DataSourceQuery}} + {{.TfName}} = fmc_{{snakeCase $name}}.test.{{.TfName}} + {{- end}} + {{- end}} } ` return config diff --git a/gen/templates/import.sh b/gen/templates/import.sh index f6d0459c..d3959903 100644 --- a/gen/templates/import.sh +++ b/gen/templates/import.sh @@ -1,5 +1,5 @@ {{- if .IsBulk -}} -terraform import fmc_{{snakeCase .Name}}.example ",[<{{snakeCase .Name}}{{if .ImportNameQuery}}_name{{else}}_id{{end}}>]" +terraform import fmc_{{snakeCase .Name}}.example ",[<{{snakeCase .Name}}_name>]" {{- else -}} terraform import fmc_{{snakeCase .Name}}.example "{{$id := false}}{{range .Attributes}}{{if .Id}}{{$id = true}}<{{.TfName}}>{{end}}{{end}}{{if not $id}}{{range .Attributes}}{{if .Reference}}<{{.TfName}}>,{{end}}{{end}}{{end}}" {{- end}} \ No newline at end of file diff --git a/gen/templates/model.go b/gen/templates/model.go index e29082c8..fd760e18 100644 --- a/gen/templates/model.go +++ b/gen/templates/model.go @@ -301,7 +301,7 @@ func (data *{{camelCase .Name}}) fromBody(ctx context.Context, res gjson.Result) parentRes.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach( func(_, v gjson.Result) bool { - {{- if $.ImportNameQuery -}} + {{- if or $.ImportNameQuery $.IsBulk -}} if v.Get("name").String() == k { {{- else -}} if v.Get("id").String() == data.Id.ValueString() && data.Id.ValueString() != "" { @@ -313,7 +313,7 @@ func (data *{{camelCase .Name}}) fromBody(ctx context.Context, res gjson.Result) }, ) if !res.Exists() { - {{- if $.ImportNameQuery -}} + {{- if or $.ImportNameQuery $.IsBulk -}} tflog.Debug(ctx, fmt.Sprintf("subresource not found, removing: name=%v", k)) {{- else -}} tflog.Debug(ctx, fmt.Sprintf("subresource not found, removing: uuid=%s, key=%v", data.Id, k)) diff --git a/gen/templates/resource.go b/gen/templates/resource.go index eaac77ec..0f4a4ef1 100644 --- a/gen/templates/resource.go +++ b/gen/templates/resource.go @@ -471,13 +471,21 @@ func (r *{{camelCase .Name}}Resource) Create(ctx context.Context, req resource.C } {{- if and .PutCreate (not .IsBulk)}} - tflog.Debug(ctx, fmt.Sprintf("%s: considering object name %s", plan.Id, plan.Name)) - if plan.Id.ValueString() == "" && plan.Name.ValueString() != "" { + {{- $attrTfName := "name" }} + {{- $attrModelName := "name" }} + {{- if hasDataSourceQuery .Attributes}} + {{- $attr := getDataSourceQueryAttribute . }} + {{- $attrTfName = $attr.TfName }} + {{- $attrModelName = $attr.ModelName }} + {{- end}} + + tflog.Debug(ctx, fmt.Sprintf("%s: considering object {{$attrTfName}} %s", plan.Id, plan.{{toGoName $attrTfName}})) + if plan.Id.ValueString() == "" && plan.{{toGoName $attrTfName}}.ValueString() != "" { offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := r.client.Get(plan.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) @@ -485,9 +493,9 @@ func (r *{{camelCase .Name}}Resource) Create(ctx context.Context, req resource.C } if value := res.Get("items"); len(value.Array()) > 0 { value.ForEach(func(k, v gjson.Result) bool { - if plan.Name.ValueString() == v.Get("name").String() { + if plan.{{toGoName $attrTfName}}.ValueString() == v.Get("{{$attrModelName}}").String() { plan.Id = types.StringValue(v.Get("id").String()) - tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%s', id: %s", plan.Id, plan.Name.ValueString(), plan.Id)) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with {{$attrTfName}} '%s', id: %s", plan.Id, plan.{{toGoName $attrTfName}}.ValueString(), plan.Id)) return false } return true @@ -500,7 +508,7 @@ func (r *{{camelCase .Name}}Resource) Create(ctx context.Context, req resource.C } if plan.Id.ValueString() == "" { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", plan.Name.ValueString())) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with {{$attrTfName}}: %s", plan.{{toGoName $attrTfName}}.ValueString())) return } } diff --git a/internal/provider/data_source_fmc_bfd_template.go b/internal/provider/data_source_fmc_bfd_template.go new file mode 100644 index 00000000..133967dd --- /dev/null +++ b/internal/provider/data_source_fmc_bfd_template.go @@ -0,0 +1,205 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &BFDTemplateDataSource{} + _ datasource.DataSourceWithConfigure = &BFDTemplateDataSource{} +) + +func NewBFDTemplateDataSource() datasource.DataSource { + return &BFDTemplateDataSource{} +} + +type BFDTemplateDataSource struct { + client *fmc.Client +} + +func (d *BFDTemplateDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_bfd_template" +} + +func (d *BFDTemplateDataSource) 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 BFD Template.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the bfd template object.", + Optional: true, + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of the object; this value is always 'BFDTemplate'.", + Computed: true, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: "The hop type.", + Computed: true, + }, + "echo": schema.StringAttribute{ + MarkdownDescription: "Enables/disables BFD echo.", + Computed: true, + }, + "interval_time": schema.StringAttribute{ + MarkdownDescription: "Interval unit of measurement of time.", + Computed: true, + }, + "min_transmit": schema.Int64Attribute{ + MarkdownDescription: "BFD Minimum Transmit unit value.", + Computed: true, + }, + "tx_rx_multiplier": schema.Int64Attribute{ + MarkdownDescription: "BFD Multipler value.", + Computed: true, + }, + "min_receive": schema.Int64Attribute{ + MarkdownDescription: "BFD Minimum Receive unit value in ranges: 50-999 miliseconds, 50000-999000 microseconds", + Computed: true, + }, + "authentication_password": schema.StringAttribute{ + MarkdownDescription: "Password for BFD Authentication (1-24 characters)", + Computed: true, + }, + "authentication_key_id": schema.Int64Attribute{ + MarkdownDescription: "Authentication Key ID", + Computed: true, + }, + "authentication_type": schema.StringAttribute{ + MarkdownDescription: "Authentication types", + Computed: true, + }, + }, + } +} +func (d *BFDTemplateDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("name"), + ), + } +} + +func (d *BFDTemplateDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *BFDTemplateDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config BFDTemplate + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.Name.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.Name.ValueString() == v.Get("name").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_bfd_template_test.go b/internal/provider/data_source_fmc_bfd_template_test.go new file mode 100644 index 00000000..e8e8259e --- /dev/null +++ b/internal/provider/data_source_fmc_bfd_template_test.go @@ -0,0 +1,112 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcBFDTemplate(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "name", "BFD_Template1")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_bfd_template.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "echo", "ENABLED")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "interval_time", "MILLISECONDS")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "min_transmit", "300")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "tx_rx_multiplier", "3")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "min_receive", "300")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "authentication_password", "Cisco123!")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "authentication_key_id", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bfd_template.test", "authentication_type", "MD5")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcBFDTemplateConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccNamedDataSourceFmcBFDTemplateConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcBFDTemplateConfig() string { + config := `resource "fmc_bfd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 300` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 300` + "\n" + config += ` authentication_password = "Cisco123!"` + "\n" + config += ` authentication_key_id = 1` + "\n" + config += ` authentication_type = "MD5"` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_bfd_template" "test" { + id = fmc_bfd_template.test.id + } + ` + return config +} + +func testAccNamedDataSourceFmcBFDTemplateConfig() string { + config := `resource "fmc_bfd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 300` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 300` + "\n" + config += ` authentication_password = "Cisco123!"` + "\n" + config += ` authentication_key_id = 1` + "\n" + config += ` authentication_type = "MD5"` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_bfd_template" "test" { + name = fmc_bfd_template.test.name + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_bgd_template.go b/internal/provider/data_source_fmc_bgd_template.go new file mode 100644 index 00000000..1704ea8e --- /dev/null +++ b/internal/provider/data_source_fmc_bgd_template.go @@ -0,0 +1,193 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &BGDTemplateDataSource{} + _ datasource.DataSourceWithConfigure = &BGDTemplateDataSource{} +) + +func NewBGDTemplateDataSource() datasource.DataSource { + return &BGDTemplateDataSource{} +} + +type BGDTemplateDataSource struct { + client *fmc.Client +} + +func (d *BGDTemplateDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_bgd_template" +} + +func (d *BGDTemplateDataSource) 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 BGD Template.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The name of the host object.", + Optional: true, + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of the object; this value is always 'BFDTemplate'.", + Computed: true, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: "SINGLE_HOP | MULTI_HOP", + Computed: true, + }, + "echo": schema.StringAttribute{ + MarkdownDescription: "(ENABLED | DISABLED)", + Computed: true, + }, + "interval_time": schema.StringAttribute{ + MarkdownDescription: "(MILLISECONDS | MICROSECONDS | NONE)", + Computed: true, + }, + "min_transmit": schema.Int64Attribute{ + MarkdownDescription: "BFD Minimum Transmit", + Computed: true, + }, + "tx_rx_multiplier": schema.Int64Attribute{ + MarkdownDescription: "BFD Multipler", + Computed: true, + }, + "min_receive": schema.Int64Attribute{ + MarkdownDescription: "BFD Minimum Receive", + Computed: true, + }, + }, + } +} +func (d *BGDTemplateDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("name"), + ), + } +} + +func (d *BGDTemplateDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *BGDTemplateDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config BGDTemplate + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.Name.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.Name.ValueString() == v.Get("name").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_bgd_template_test.go b/internal/provider/data_source_fmc_bgd_template_test.go new file mode 100644 index 00000000..4fbcca9a --- /dev/null +++ b/internal/provider/data_source_fmc_bgd_template_test.go @@ -0,0 +1,102 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcBGDTemplate(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "name", "BFD_Template1")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_bgd_template.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "echo", "ENABLED")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "interval_time", "MILLISECONDS")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "min_transmit", "100000")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "tx_rx_multiplier", "3")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_bgd_template.test", "min_receive", "100000")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcBGDTemplateConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccNamedDataSourceFmcBGDTemplateConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcBGDTemplateConfig() string { + config := `resource "fmc_bgd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 100000` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 100000` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_bgd_template" "test" { + id = fmc_bgd_template.test.id + } + ` + return config +} + +func testAccNamedDataSourceFmcBGDTemplateConfig() string { + config := `resource "fmc_bgd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 100000` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 100000` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_bgd_template" "test" { + name = fmc_bgd_template.test.name + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_device_bfd.go b/internal/provider/data_source_fmc_device_bfd.go new file mode 100644 index 00000000..63d20363 --- /dev/null +++ b/internal/provider/data_source_fmc_device_bfd.go @@ -0,0 +1,197 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &DeviceBFDDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceBFDDataSource{} +) + +func NewDeviceBFDDataSource() datasource.DataSource { + return &DeviceBFDDataSource{} +} + +type DeviceBFDDataSource struct { + client *fmc.Client +} + +func (d *DeviceBFDDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bfd" +} + +func (d *DeviceBFDDataSource) 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 Device BFD.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: "UUID of the parent device (fmc_device.example.id).", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of the object; this value is always 'BFDPolicy'", + Computed: true, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: "BFD Hop type.", + Computed: true, + }, + "bfd_template_id": schema.StringAttribute{ + MarkdownDescription: "ID of the BFD Template", + Computed: true, + }, + "interface_logical_name": schema.StringAttribute{ + MarkdownDescription: "Logical Name of the interface of BFD assignment if SINGLE_HOP selected.", + Optional: true, + Computed: true, + }, + "destination_host_object_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the destination host object if MULTI_HOP selected.", + Computed: true, + }, + "source_host_object_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the source host object if MULTI_HOP selected.", + Computed: true, + }, + "interface_id": schema.StringAttribute{ + MarkdownDescription: "ID of the interface of BFD assignment if SINGLE_HOP selected.", + Computed: true, + }, + "slow_timer": schema.Int64Attribute{ + MarkdownDescription: "BFD Slow Timer value in range: 1000-30000, default: 1000", + Computed: true, + }, + }, + } +} +func (d *DeviceBFDDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("interface_logical_name"), + ), + } +} + +func (d *DeviceBFDDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *DeviceBFDDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceBFD + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.InterfaceLogicalName.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.InterfaceLogicalName.ValueString() == v.Get("ifname").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with interface_logical_name '%v', id: %v", config.Id.String(), config.InterfaceLogicalName.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with interface_logical_name: %s", config.InterfaceLogicalName.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_device_bfd_test.go b/internal/provider/data_source_fmc_device_bfd_test.go new file mode 100644 index 00000000..3522d2a3 --- /dev/null +++ b/internal/provider/data_source_fmc_device_bfd_test.go @@ -0,0 +1,116 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcDeviceBFD(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bfd.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "bfd_template_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "interface_logical_name", "outside")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "destination_host_object_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "source_host_object_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "interface_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bfd.test", "slow_timer", "")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcDeviceBFDPrerequisitesConfig + testAccDataSourceFmcDeviceBFDConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccDataSourceFmcDeviceBFDPrerequisitesConfig + testAccNamedDataSourceFmcDeviceBFDConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccDataSourceFmcDeviceBFDPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcDeviceBFDConfig() string { + config := `resource "fmc_device_bfd" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_logical_name = "outside"` + "\n" + config += ` destination_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` source_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` slow_timer = ` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bfd" "test" { + id = fmc_device_bfd.test.id + device_id = var.device_id + } + ` + return config +} + +func testAccNamedDataSourceFmcDeviceBFDConfig() string { + config := `resource "fmc_device_bfd" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_logical_name = "outside"` + "\n" + config += ` destination_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` source_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` slow_timer = ` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bfd" "test" { + device_id = var.device_id + interface_logical_name = fmc_device_bfd.test.interface_logical_name + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_device_bgp.go b/internal/provider/data_source_fmc_device_bgp.go new file mode 100644 index 00000000..d3f386c6 --- /dev/null +++ b/internal/provider/data_source_fmc_device_bgp.go @@ -0,0 +1,561 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &DeviceBGPDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceBGPDataSource{} +) + +func NewDeviceBGPDataSource() datasource.DataSource { + return &DeviceBGPDataSource{} +} + +type DeviceBGPDataSource struct { + client *fmc.Client +} + +func (d *DeviceBGPDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bgp" +} + +func (d *DeviceBGPDataSource) 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 Device BGP.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: "UUID of the parent device (fmc_device.example.id).", + Required: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "Name of the object; this is always 'bgp'", + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of the object; this is always 'bgp'", + Computed: true, + }, + "as_number": schema.StringAttribute{ + MarkdownDescription: "Autonomus System (AS) Number", + Optional: true, + Computed: true, + }, + "ipv4_address_family_type": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "ipv4_learned_route_map_id": schema.StringAttribute{ + MarkdownDescription: "Learned Route Map ID", + Computed: true, + }, + "ipv4_default_information_orginate": schema.BoolAttribute{ + MarkdownDescription: "Generate default routes", + Computed: true, + }, + "ipv4_auto_aummary": schema.BoolAttribute{ + MarkdownDescription: "Summarize subnet routes into network level routes", + Computed: true, + }, + "ipv4_bgp_supress_inactive": schema.BoolAttribute{ + MarkdownDescription: "Suppresing advertise inactive routes", + Computed: true, + }, + "ipv4_synchronization": schema.BoolAttribute{ + MarkdownDescription: "Synchronize between BGP and IGP systems", + Computed: true, + }, + "ipv4_bgp_redistribute_internal": schema.BoolAttribute{ + MarkdownDescription: "Redistribute IBGP into IGP. (Use filtering to limit the number of prefixes that are redistributed)", + Computed: true, + }, + "ipv4_external_distance": schema.Int64Attribute{ + MarkdownDescription: "Administrative route distance for external routes", + Computed: true, + }, + "ipv4_internal_distance": schema.Int64Attribute{ + MarkdownDescription: "Administrative route distance for internal routes", + Computed: true, + }, + "ipv4_local_distance": schema.Int64Attribute{ + MarkdownDescription: "Administrative route distance for local routes", + Computed: true, + }, + "ipv4_forward_packets_over_multipath_ibgp": schema.Int64Attribute{ + MarkdownDescription: "Number of paths to use for IBGP", + Computed: true, + }, + "ipv4_forward_packets_over_multipath_ebgp": schema.Int64Attribute{ + MarkdownDescription: "Number of paths to use for EBGP", + Computed: true, + }, + "ipv4_neighbors": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "neighbor_address": schema.StringAttribute{ + MarkdownDescription: "IP address of the BGP neighbor", + Computed: true, + }, + "neighbor_remote_as": schema.StringAttribute{ + MarkdownDescription: "AS number of the BGP neighbor", + Computed: true, + }, + "neighbor_bfd": schema.StringAttribute{ + MarkdownDescription: "BFD Fallover", + Computed: true, + }, + "update_source_interface_id": schema.StringAttribute{ + MarkdownDescription: "Interface ID for the update source", + Computed: true, + }, + "enable_address_family": schema.BoolAttribute{ + MarkdownDescription: "Enable IPv4 address family", + Computed: true, + }, + "neighbor_shutdown": schema.BoolAttribute{ + MarkdownDescription: "Shutdown administratively", + Computed: true, + }, + "neighbor_description": schema.StringAttribute{ + MarkdownDescription: "Description of the neighbor", + Computed: true, + }, + "neighbor_filter_access_lists": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "access_list_id": schema.StringAttribute{ + MarkdownDescription: "Access List ID", + Computed: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: "Filter direction", + Computed: true, + }, + }, + }, + }, + "neighbor_filter_route_map_lists": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "route_map_id": schema.StringAttribute{ + MarkdownDescription: "Route Map ID", + Computed: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: "Filter direction", + Computed: true, + }, + }, + }, + }, + "neighbor_filter_prefix_lists": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "prefix_list_id": schema.StringAttribute{ + MarkdownDescription: "Route Map ID", + Computed: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: "Filter direction", + Computed: true, + }, + }, + }, + }, + "neighbor_filter_as_path_lists": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "update_direction": schema.StringAttribute{ + MarkdownDescription: "Filter direction", + Computed: true, + }, + "as_path_id": schema.StringAttribute{ + MarkdownDescription: "AS Path ID", + Computed: true, + }, + }, + }, + }, + "neighbor_filter_max_prefix": schema.Int64Attribute{ + MarkdownDescription: "Maximum number of prefixes allowed from the neighbor", + Computed: true, + }, + "neighbor_filter_warning_only": schema.BoolAttribute{ + MarkdownDescription: "Give only warning message when prefix limit exceeded or terminate peering when prefix limit is exceeded.", + Computed: true, + }, + "neighbor_filter_threshold_value": schema.Int64Attribute{ + MarkdownDescription: "Threshold value for the maximum number of prefixes allowed from the neighbor", + Computed: true, + }, + "neighbor_filter_restart_interval": schema.Int64Attribute{ + MarkdownDescription: "Time interval to restart the maximum prefix limit in Minutes", + Computed: true, + }, + "neighbor_routes_advertisement_interval": schema.Int64Attribute{ + MarkdownDescription: "Time interval to advertise routes in seconds", + Computed: true, + }, + "neighbor_routes_remove_private_as": schema.BoolAttribute{ + MarkdownDescription: "Remove private AS numbers from outgoing routing updates", + Computed: true, + }, + "neighbor_generate_default_route_map_id": schema.StringAttribute{ + MarkdownDescription: "Generate default routes - Route Map", + Computed: true, + }, + "neighbor_routes_advertise_map_use_exist": schema.BoolAttribute{ + MarkdownDescription: "Use Exist Map or Non-Exist Map", + Computed: true, + }, + "neighbor_routes_advertise_map_id": schema.StringAttribute{ + MarkdownDescription: "Specified route maps are advertised when the prefix exists in the Advertise Map and Exist Map.", + Computed: true, + }, + "neighbor_routes_advertise_exist_nonexist_map_id": schema.StringAttribute{ + MarkdownDescription: "Specified route maps are advertised when the prefix exists only in the Advertise Map.", + Computed: true, + }, + "neighbor_keepalive_interval": schema.Int64Attribute{ + MarkdownDescription: "Time interval to send keepalive messages in seconds", + Computed: true, + }, + "neighbor_hold_time": schema.Int64Attribute{ + MarkdownDescription: "Time interval to hold the neighbor in seconds", + Computed: true, + }, + "neighbor_min_hold_time": schema.Int64Attribute{ + MarkdownDescription: "Minimum hold time in seconds", + Computed: true, + }, + "neighbor_authentication_password": schema.StringAttribute{ + MarkdownDescription: "Setting password enables authentication.", + Computed: true, + }, + "neighbor_send_community_attribute": schema.BoolAttribute{ + MarkdownDescription: "Send Community attribute to this neighbor", + Computed: true, + }, + "neighbor_nexthop_self": schema.BoolAttribute{ + MarkdownDescription: "Use itself as next hop for this neighbor", + Computed: true, + }, + "neighbor_disable_connection_verification": schema.BoolAttribute{ + MarkdownDescription: "Disable Connection Verification", + Computed: true, + }, + "neighbor_tcp_mtu_path_discovery": schema.BoolAttribute{ + MarkdownDescription: "Use TCP path MTU discovery.", + Computed: true, + }, + "neighbor_max_hop_count": schema.Int64Attribute{ + MarkdownDescription: "Maximum number of hops to reach the neighbor", + Computed: true, + }, + "neighbor_tcp_transport_mode": schema.BoolAttribute{ + MarkdownDescription: "True set it to active, False to passive.", + Computed: true, + }, + "neighbor_weight": schema.Int64Attribute{ + MarkdownDescription: "Weight of the neighbor", + Computed: true, + }, + "neighbor_version": schema.StringAttribute{ + MarkdownDescription: "Set BPG version: 0 - default, 4 - IPv4", + Computed: true, + }, + "neighbor_customized_local_as_number": schema.StringAttribute{ + MarkdownDescription: "Customize the AS number for the routes received from neighbor", + Computed: true, + }, + "neighbor_customized_no_prepend": schema.BoolAttribute{ + MarkdownDescription: "Do not prepend local AS number to routes received from neighbor", + Computed: true, + }, + "neighbor_customized_replace_as": schema.BoolAttribute{ + MarkdownDescription: "Replace real AS number with local AS number in routes received from neighbor", + Computed: true, + }, + "neighbor_customized_accept_both_as": schema.BoolAttribute{ + MarkdownDescription: "Accept either real AS number or local AS number in routes experienced from neighbor", + Computed: true, + }, + }, + }, + }, + "ipv4_aggregate_addresses": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "generate_as": schema.BoolAttribute{ + MarkdownDescription: "Generate AS set path information", + Computed: true, + }, + "filter": schema.BoolAttribute{ + MarkdownDescription: "Filter all routes from updates (summary only)", + Computed: true, + }, + "network_id": schema.StringAttribute{ + MarkdownDescription: "Network ID", + Computed: true, + }, + "advertise_map_id": schema.StringAttribute{ + MarkdownDescription: "Advertise Map ID", + Computed: true, + }, + "attribute_map_id": schema.StringAttribute{ + MarkdownDescription: "Attribute Map ID", + Computed: true, + }, + "suppress_map_id": schema.StringAttribute{ + MarkdownDescription: "Suppress Map ID", + Computed: true, + }, + }, + }, + }, + "ipv4_filterings": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "access_list_id": schema.StringAttribute{ + MarkdownDescription: "Standard Access List ID", + Computed: true, + }, + "network_direction": schema.StringAttribute{ + MarkdownDescription: "Filtering directrion", + Computed: true, + }, + "protocol": schema.StringAttribute{ + MarkdownDescription: "Protocol", + Computed: true, + }, + "prorocol_process": schema.StringAttribute{ + MarkdownDescription: "Process ID", + Computed: true, + }, + }, + }, + }, + "ipv4_networks": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "network_id": schema.StringAttribute{ + MarkdownDescription: "Network object ID", + Computed: true, + }, + "route_map_id": schema.StringAttribute{ + MarkdownDescription: "Route Map ID", + Computed: true, + }, + }, + }, + }, + "ipv4_redistributions": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "source_protocol": schema.StringAttribute{ + MarkdownDescription: "Protocol to redistribute", + Computed: true, + }, + "route_map_id": schema.StringAttribute{ + MarkdownDescription: "Route Map ID", + Computed: true, + }, + "metric": schema.Int64Attribute{ + MarkdownDescription: "Metric value", + Computed: true, + }, + "process_id": schema.StringAttribute{ + MarkdownDescription: "process ID", + Computed: true, + }, + "match_external1": schema.BoolAttribute{ + MarkdownDescription: "Match OSPF External 1 metrics", + Computed: true, + }, + "match_external2": schema.BoolAttribute{ + MarkdownDescription: "Match OSPF External 2 metrics", + Computed: true, + }, + "match_internal": schema.BoolAttribute{ + MarkdownDescription: "Match OSPF Internal metrics", + Computed: true, + }, + "match_nssa_external1": schema.BoolAttribute{ + MarkdownDescription: "Match OSPF NSSA External 1 metrics", + Computed: true, + }, + "match_nssa_external2": schema.BoolAttribute{ + MarkdownDescription: "Match OSPF NSSA External 2 metrics", + Computed: true, + }, + }, + }, + }, + "ipv4_route_injections": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "inject_route_map_id": schema.StringAttribute{ + MarkdownDescription: "Inject Route Map ID", + Computed: true, + }, + "exist_route_map_id": schema.StringAttribute{ + MarkdownDescription: "Exist Route Map ID", + Computed: true, + }, + }, + }, + }, + }, + } +} +func (d *DeviceBGPDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("as_number"), + ), + } +} + +func (d *DeviceBGPDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *DeviceBGPDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceBGP + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.AsNumber.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.AsNumber.ValueString() == v.Get("asNumber").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with as_number '%v', id: %v", config.Id.String(), config.AsNumber.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with as_number: %s", config.AsNumber.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_device_bgp_general_settings.go b/internal/provider/data_source_fmc_device_bgp_general_settings.go new file mode 100644 index 00000000..f230dbee --- /dev/null +++ b/internal/provider/data_source_fmc_device_bgp_general_settings.go @@ -0,0 +1,261 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &DeviceBGPGeneralSettingsDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceBGPGeneralSettingsDataSource{} +) + +func NewDeviceBGPGeneralSettingsDataSource() datasource.DataSource { + return &DeviceBGPGeneralSettingsDataSource{} +} + +type DeviceBGPGeneralSettingsDataSource struct { + client *fmc.Client +} + +func (d *DeviceBGPGeneralSettingsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bgp_general_settings" +} + +func (d *DeviceBGPGeneralSettingsDataSource) 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 Device BGP General Settings.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: "UUID of the parent device (fmc_device.example.id).", + Required: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "Object name; Always set to 'AsaBGPGeneralTable'", + Computed: true, + }, + "as_number": schema.StringAttribute{ + MarkdownDescription: "Autonomous System (AS) number in asplain or asdot format", + Optional: true, + Computed: true, + }, + "router_id": schema.StringAttribute{ + MarkdownDescription: "String value for the routerID. Possible values can be 'AUTOMATIC' or valid ipv4 address", + Computed: true, + }, + "scanning_interval": schema.Int64Attribute{ + MarkdownDescription: "Scanning interval of BGP routers for next hop validation in Seconds.", + Computed: true, + }, + "as_number_in_path_attribute": schema.Int64Attribute{ + MarkdownDescription: "Range to discard routes that have as-path segments that exceed a specified value.", + Computed: true, + }, + "log_neighbor_changes": schema.BoolAttribute{ + MarkdownDescription: "Enable logging of BGP neighbor status changes.", + Computed: true, + }, + "tcp_path_mtu_discovery": schema.BoolAttribute{ + MarkdownDescription: "Use TCP path MTU discovery.", + Computed: true, + }, + "reset_session_upon_failover": schema.BoolAttribute{ + MarkdownDescription: "Reset session upon failover", + Computed: true, + }, + "enforce_first_peer_as": schema.BoolAttribute{ + MarkdownDescription: "Discard updates received from an external BGP (eBGP) peers that do not list their autonomous system (AS) number.", + Computed: true, + }, + "use_dot_notation": schema.BoolAttribute{ + MarkdownDescription: "Change format of BGP 4-byte autonomous system numbers from asplain (decimal values) to dot notation.", + Computed: true, + }, + "aggregate_timer": schema.Int64Attribute{ + MarkdownDescription: "Interval at which BGP routes will be aggregated or to disable timer-based router aggregation (in seconds).", + Computed: true, + }, + "default_local_preference": schema.Int64Attribute{ + MarkdownDescription: "Default local preference", + Computed: true, + }, + "compare_med_from_different_neighbors": schema.BoolAttribute{ + MarkdownDescription: "Allow comparing MED from different neighbors", + Computed: true, + }, + "compare_router_id_in_path": schema.BoolAttribute{ + MarkdownDescription: "Compare Router ID for identical EBGP paths", + Computed: true, + }, + "pick_best_med": schema.BoolAttribute{ + MarkdownDescription: "Pick the best-MED path among paths advertised by neighbor AS", + Computed: true, + }, + "missing_med_as_best": schema.BoolAttribute{ + MarkdownDescription: "Treat missing MED as the best preferred path", + Computed: true, + }, + "keepalive_interval": schema.Int64Attribute{ + MarkdownDescription: "Keepalive interval in seconds", + Computed: true, + }, + "hold_time": schema.Int64Attribute{ + MarkdownDescription: "Hold time in seconds", + Computed: true, + }, + "min_hold_time": schema.Int64Attribute{ + MarkdownDescription: "Minimum hold time (0 or 3-65535 seconds)", + Computed: true, + }, + "next_hop_address_tracking": schema.BoolAttribute{ + MarkdownDescription: "Enable next hop address tracking", + Computed: true, + }, + "next_hop_delay_interval": schema.Int64Attribute{ + MarkdownDescription: "Next hop delay interval in seconds", + Computed: true, + }, + "graceful_restart": schema.BoolAttribute{ + MarkdownDescription: "Enable graceful restart", + Computed: true, + }, + "graceful_restart_restart_time": schema.Int64Attribute{ + MarkdownDescription: "Graceful Restart Time in seconds", + Computed: true, + }, + "graceful_restart_stale_path_time": schema.Int64Attribute{ + MarkdownDescription: "Stalepath Time in seconds", + Computed: true, + }, + }, + } +} +func (d *DeviceBGPGeneralSettingsDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("as_number"), + ), + } +} + +func (d *DeviceBGPGeneralSettingsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *DeviceBGPGeneralSettingsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceBGPGeneralSettings + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.AsNumber.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.AsNumber.ValueString() == v.Get("asNumber").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with as_number '%v', id: %v", config.Id.String(), config.AsNumber.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with as_number: %s", config.AsNumber.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_device_bgp_general_settings_test.go b/internal/provider/data_source_fmc_device_bgp_general_settings_test.go new file mode 100644 index 00000000..1e34b1c7 --- /dev/null +++ b/internal/provider/data_source_fmc_device_bgp_general_settings_test.go @@ -0,0 +1,152 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcDeviceBGPGeneralSettings(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bgp_general_settings.test", "name")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "as_number", "65535")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "router_id", "AUTOMATIC")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "scanning_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "as_number_in_path_attribute", "50")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "log_neighbor_changes", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "tcp_path_mtu_discovery", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "reset_session_upon_failover", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "enforce_first_peer_as", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "use_dot_notation", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "aggregate_timer", "30")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "default_local_preference", "100")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "compare_med_from_different_neighbors", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "compare_router_id_in_path", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "pick_best_med", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "missing_med_as_best", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "keepalive_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "hold_time", "180")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "min_hold_time", "0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp_general_settings.test", "next_hop_delay_interval", "5")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcDeviceBGPGeneralSettingsPrerequisitesConfig + testAccDataSourceFmcDeviceBGPGeneralSettingsConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccDataSourceFmcDeviceBGPGeneralSettingsPrerequisitesConfig + testAccNamedDataSourceFmcDeviceBGPGeneralSettingsConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccDataSourceFmcDeviceBGPGeneralSettingsPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcDeviceBGPGeneralSettingsConfig() string { + config := `resource "fmc_device_bgp_general_settings" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` as_number = "65535"` + "\n" + config += ` router_id = "AUTOMATIC"` + "\n" + config += ` scanning_interval = 60` + "\n" + config += ` as_number_in_path_attribute = 50` + "\n" + config += ` log_neighbor_changes = false` + "\n" + config += ` tcp_path_mtu_discovery = true` + "\n" + config += ` reset_session_upon_failover = true` + "\n" + config += ` enforce_first_peer_as = true` + "\n" + config += ` use_dot_notation = false` + "\n" + config += ` aggregate_timer = 30` + "\n" + config += ` default_local_preference = 100` + "\n" + config += ` compare_med_from_different_neighbors = true` + "\n" + config += ` compare_router_id_in_path = true` + "\n" + config += ` pick_best_med = true` + "\n" + config += ` missing_med_as_best = false` + "\n" + config += ` keepalive_interval = 60` + "\n" + config += ` hold_time = 180` + "\n" + config += ` min_hold_time = 0` + "\n" + config += ` next_hop_delay_interval = 5` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bgp_general_settings" "test" { + id = fmc_device_bgp_general_settings.test.id + device_id = var.device_id + } + ` + return config +} + +func testAccNamedDataSourceFmcDeviceBGPGeneralSettingsConfig() string { + config := `resource "fmc_device_bgp_general_settings" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` as_number = "65535"` + "\n" + config += ` router_id = "AUTOMATIC"` + "\n" + config += ` scanning_interval = 60` + "\n" + config += ` as_number_in_path_attribute = 50` + "\n" + config += ` log_neighbor_changes = false` + "\n" + config += ` tcp_path_mtu_discovery = true` + "\n" + config += ` reset_session_upon_failover = true` + "\n" + config += ` enforce_first_peer_as = true` + "\n" + config += ` use_dot_notation = false` + "\n" + config += ` aggregate_timer = 30` + "\n" + config += ` default_local_preference = 100` + "\n" + config += ` compare_med_from_different_neighbors = true` + "\n" + config += ` compare_router_id_in_path = true` + "\n" + config += ` pick_best_med = true` + "\n" + config += ` missing_med_as_best = false` + "\n" + config += ` keepalive_interval = 60` + "\n" + config += ` hold_time = 180` + "\n" + config += ` min_hold_time = 0` + "\n" + config += ` next_hop_delay_interval = 5` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bgp_general_settings" "test" { + device_id = var.device_id + as_number = fmc_device_bgp_general_settings.test.as_number + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_device_bgp_test.go b/internal/provider/data_source_fmc_device_bgp_test.go new file mode 100644 index 00000000..15d0146c --- /dev/null +++ b/internal/provider/data_source_fmc_device_bgp_test.go @@ -0,0 +1,206 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcDeviceBGP(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bgp.test", "name")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bgp.test", "type")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bgp.test", "as_number")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_bgp.test", "ipv4_address_family_type")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_default_information_orginate", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_auto_aummary", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_bgp_supress_inactive", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_synchronization", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_bgp_redistribute_internal", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_external_distance", "20")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_internal_distance", "200")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_local_distance", "200")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_forward_packets_over_multipath_ibgp", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_forward_packets_over_multipath_ebgp", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_address", "10.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_remote_as", "65534")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_bfd", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.enable_address_family", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_shutdown", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_description", "My BGP Peer")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_max_prefix", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_warning_only", "true")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_threshold_value", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_restart_interval", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_routes_advertisement_interval", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_routes_remove_private_as", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_keepalive_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_hold_time", "180")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_min_hold_time", "3")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_send_community_attribute", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_nexthop_self", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_disable_connection_verification", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_tcp_mtu_path_discovery", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_max_hop_count", "1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_tcp_transport_mode", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_weight", "0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_version", "0")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcDeviceBGPPrerequisitesConfig + testAccDataSourceFmcDeviceBGPConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccDataSourceFmcDeviceBGPPrerequisitesConfig + testAccNamedDataSourceFmcDeviceBGPConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccDataSourceFmcDeviceBGPPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id + +resource "fmc_device_bgp_general_settings" "test" { + device_id = var.device_id + as_number = "6353" +} +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcDeviceBGPConfig() string { + config := `resource "fmc_device_bgp" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` ipv4_default_information_orginate = false` + "\n" + config += ` ipv4_auto_aummary = false` + "\n" + config += ` ipv4_bgp_supress_inactive = false` + "\n" + config += ` ipv4_synchronization = false` + "\n" + config += ` ipv4_bgp_redistribute_internal = false` + "\n" + config += ` ipv4_external_distance = 20` + "\n" + config += ` ipv4_internal_distance = 200` + "\n" + config += ` ipv4_local_distance = 200` + "\n" + config += ` ipv4_forward_packets_over_multipath_ibgp = 1` + "\n" + config += ` ipv4_forward_packets_over_multipath_ebgp = 1` + "\n" + config += ` ipv4_neighbors = [{` + "\n" + config += ` neighbor_address = "10.1.1.1"` + "\n" + config += ` neighbor_remote_as = "65534"` + "\n" + config += ` neighbor_bfd = "SINGLE_HOP"` + "\n" + config += ` enable_address_family = true` + "\n" + config += ` neighbor_shutdown = false` + "\n" + config += ` neighbor_description = "My BGP Peer"` + "\n" + config += ` neighbor_filter_max_prefix = 1` + "\n" + config += ` neighbor_filter_warning_only = true` + "\n" + config += ` neighbor_filter_threshold_value = 1` + "\n" + config += ` neighbor_filter_restart_interval = 1` + "\n" + config += ` neighbor_routes_advertisement_interval = 1` + "\n" + config += ` neighbor_routes_remove_private_as = false` + "\n" + config += ` neighbor_keepalive_interval = 60` + "\n" + config += ` neighbor_hold_time = 180` + "\n" + config += ` neighbor_min_hold_time = 3` + "\n" + config += ` neighbor_send_community_attribute = false` + "\n" + config += ` neighbor_nexthop_self = false` + "\n" + config += ` neighbor_disable_connection_verification = false` + "\n" + config += ` neighbor_tcp_mtu_path_discovery = false` + "\n" + config += ` neighbor_max_hop_count = 1` + "\n" + config += ` neighbor_tcp_transport_mode = false` + "\n" + config += ` neighbor_weight = 0` + "\n" + config += ` neighbor_version = "0"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bgp" "test" { + id = fmc_device_bgp.test.id + device_id = var.device_id + } + ` + return config +} + +func testAccNamedDataSourceFmcDeviceBGPConfig() string { + config := `resource "fmc_device_bgp" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` ipv4_default_information_orginate = false` + "\n" + config += ` ipv4_auto_aummary = false` + "\n" + config += ` ipv4_bgp_supress_inactive = false` + "\n" + config += ` ipv4_synchronization = false` + "\n" + config += ` ipv4_bgp_redistribute_internal = false` + "\n" + config += ` ipv4_external_distance = 20` + "\n" + config += ` ipv4_internal_distance = 200` + "\n" + config += ` ipv4_local_distance = 200` + "\n" + config += ` ipv4_forward_packets_over_multipath_ibgp = 1` + "\n" + config += ` ipv4_forward_packets_over_multipath_ebgp = 1` + "\n" + config += ` ipv4_neighbors = [{` + "\n" + config += ` neighbor_address = "10.1.1.1"` + "\n" + config += ` neighbor_remote_as = "65534"` + "\n" + config += ` neighbor_bfd = "SINGLE_HOP"` + "\n" + config += ` enable_address_family = true` + "\n" + config += ` neighbor_shutdown = false` + "\n" + config += ` neighbor_description = "My BGP Peer"` + "\n" + config += ` neighbor_filter_max_prefix = 1` + "\n" + config += ` neighbor_filter_warning_only = true` + "\n" + config += ` neighbor_filter_threshold_value = 1` + "\n" + config += ` neighbor_filter_restart_interval = 1` + "\n" + config += ` neighbor_routes_advertisement_interval = 1` + "\n" + config += ` neighbor_routes_remove_private_as = false` + "\n" + config += ` neighbor_keepalive_interval = 60` + "\n" + config += ` neighbor_hold_time = 180` + "\n" + config += ` neighbor_min_hold_time = 3` + "\n" + config += ` neighbor_send_community_attribute = false` + "\n" + config += ` neighbor_nexthop_self = false` + "\n" + config += ` neighbor_disable_connection_verification = false` + "\n" + config += ` neighbor_tcp_mtu_path_discovery = false` + "\n" + config += ` neighbor_max_hop_count = 1` + "\n" + config += ` neighbor_tcp_transport_mode = false` + "\n" + config += ` neighbor_weight = 0` + "\n" + config += ` neighbor_version = "0"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_bgp" "test" { + device_id = var.device_id + as_number = fmc_device_bgp.test.as_number + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_device_etherchannel_interface.go b/internal/provider/data_source_fmc_device_etherchannel_interface.go index 0b86eb41..30079067 100644 --- a/internal/provider/data_source_fmc_device_etherchannel_interface.go +++ b/internal/provider/data_source_fmc_device_etherchannel_interface.go @@ -460,7 +460,7 @@ func (d *DeviceEtherChannelInterfaceDataSource) Read(ctx context.Context, req da offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_device_etherchannel_interface_test.go b/internal/provider/data_source_fmc_device_etherchannel_interface_test.go index 89efb6b3..4b26c4e4 100644 --- a/internal/provider/data_source_fmc_device_etherchannel_interface_test.go +++ b/internal/provider/data_source_fmc_device_etherchannel_interface_test.go @@ -123,8 +123,8 @@ func testAccNamedDataSourceFmcDeviceEtherChannelInterfaceConfig() string { config += ` data "fmc_device_etherchannel_interface" "test" { - name = fmc_device_etherchannel_interface.test.name device_id = var.device_id + name = fmc_device_etherchannel_interface.test.name } ` return config diff --git a/internal/provider/data_source_fmc_device_ha_pair_monitoring.go b/internal/provider/data_source_fmc_device_ha_pair_monitoring.go new file mode 100644 index 00000000..4010defb --- /dev/null +++ b/internal/provider/data_source_fmc_device_ha_pair_monitoring.go @@ -0,0 +1,205 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &DeviceHAPairMonitoringDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceHAPairMonitoringDataSource{} +) + +func NewDeviceHAPairMonitoringDataSource() datasource.DataSource { + return &DeviceHAPairMonitoringDataSource{} +} + +type DeviceHAPairMonitoringDataSource struct { + client *fmc.Client +} + +func (d *DeviceHAPairMonitoringDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pair_monitoring" +} + +func (d *DeviceHAPairMonitoringDataSource) 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 Device HA Pair Monitoring.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Optional: true, + Computed: true, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: "UUID of the parent HA device (fmc_device.example.id).", + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of the resource.", + Computed: true, + }, + "logical_name": schema.StringAttribute{ + MarkdownDescription: "Logical Name of the monitored interface.", + Optional: true, + Computed: true, + }, + "monitor_interface": schema.BoolAttribute{ + MarkdownDescription: "Monitor this interface for failures.", + Computed: true, + }, + "ipv4_active_address": schema.StringAttribute{ + MarkdownDescription: "Active IPv4 address from the interface.", + Computed: true, + }, + "ipv4_standby_address": schema.StringAttribute{ + MarkdownDescription: "Standby IPv4 address. It has to be in the same subnet as primaty IP configured on this interface.", + Computed: true, + }, + "ipv4_netmask": schema.StringAttribute{ + MarkdownDescription: "IPv4 Network Mask assigned on the interface.", + Computed: true, + }, + "ipv6_addresses": schema.ListNestedAttribute{ + MarkdownDescription: "", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "active_address": schema.StringAttribute{ + MarkdownDescription: "Active IPv6 address with prefix. Address has to be configured on the interface.", + Computed: true, + }, + "standby_address": schema.StringAttribute{ + MarkdownDescription: "Standby IPv6 address. Address has to be from the same subnet as active IPv6 address.", + Computed: true, + }, + }, + }, + }, + }, + } +} +func (d *DeviceHAPairMonitoringDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("logical_name"), + ), + } +} + +func (d *DeviceHAPairMonitoringDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + d.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (d *DeviceHAPairMonitoringDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceHAPairMonitoring + + // Read config + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !config.Domain.IsNull() && config.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(config.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) + if config.Id.IsNull() && !config.LogicalName.IsNull() { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := d.client.Get(config.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if config.LogicalName.ValueString() == v.Get("name").String() { + config.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with logical_name '%v', id: %v", config.Id.String(), config.LogicalName.ValueString(), config.Id.String())) + return false + } + return true + }) + } + if !config.Id.IsNull() || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if config.Id.IsNull() { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with logical_name: %s", config.LogicalName.ValueString())) + return + } + } + urlPath := config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()) + res, err := d.client.Get(urlPath, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) + return + } + + config.fromBody(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString())) + + diags = resp.State.Set(ctx, &config) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end read diff --git a/internal/provider/data_source_fmc_device_ha_pair_monitoring_test.go b/internal/provider/data_source_fmc_device_ha_pair_monitoring_test.go new file mode 100644 index 00000000..48370389 --- /dev/null +++ b/internal/provider/data_source_fmc_device_ha_pair_monitoring_test.go @@ -0,0 +1,116 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource + +func TestAccDataSourceFmcDeviceHAPairMonitoring(t *testing.T) { + if os.Getenv("TF_VAR_device_ha_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_ha_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_ha_pair_monitoring.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair_monitoring.test", "logical_name", "outside")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair_monitoring.test", "monitor_interface", "true")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_ha_pair_monitoring.test", "ipv4_active_address")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair_monitoring.test", "ipv4_standby_address", "10.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_device_ha_pair_monitoring.test", "ipv4_netmask")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair_monitoring.test", "ipv6_addresses.0.active_address", "2006::1/30")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair_monitoring.test", "ipv6_addresses.0.standby_address", "2006::2")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcDeviceHAPairMonitoringPrerequisitesConfig + testAccDataSourceFmcDeviceHAPairMonitoringConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccDataSourceFmcDeviceHAPairMonitoringPrerequisitesConfig + testAccNamedDataSourceFmcDeviceHAPairMonitoringConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + }, + }) +} + +// End of section. //template:end testAccDataSource + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccDataSourceFmcDeviceHAPairMonitoringPrerequisitesConfig = ` +variable "device_ha_id" { default = null } // tests will set $TF_VAR_device_ha_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig + +func testAccDataSourceFmcDeviceHAPairMonitoringConfig() string { + config := `resource "fmc_device_ha_pair_monitoring" "test" {` + "\n" + config += ` device_id = var.device_ha_id` + "\n" + config += ` logical_name = "outside"` + "\n" + config += ` monitor_interface = true` + "\n" + config += ` ipv4_standby_address = "10.1.1.2"` + "\n" + config += ` ipv6_addresses = [{` + "\n" + config += ` active_address = "2006::1/30"` + "\n" + config += ` standby_address = "2006::2"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_ha_pair_monitoring" "test" { + id = fmc_device_ha_pair_monitoring.test.id + device_id = var.device_ha_id + } + ` + return config +} + +func testAccNamedDataSourceFmcDeviceHAPairMonitoringConfig() string { + config := `resource "fmc_device_ha_pair_monitoring" "test" {` + "\n" + config += ` device_id = var.device_ha_id` + "\n" + config += ` logical_name = "outside"` + "\n" + config += ` monitor_interface = true` + "\n" + config += ` ipv4_standby_address = "10.1.1.2"` + "\n" + config += ` ipv6_addresses = [{` + "\n" + config += ` active_address = "2006::1/30"` + "\n" + config += ` standby_address = "2006::2"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_ha_pair_monitoring" "test" { + device_id = var.device_ha_id + logical_name = fmc_device_ha_pair_monitoring.test.logical_name + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/data_source_fmc_device_physical_interface.go b/internal/provider/data_source_fmc_device_physical_interface.go index efe25dda..50709a81 100644 --- a/internal/provider/data_source_fmc_device_physical_interface.go +++ b/internal/provider/data_source_fmc_device_physical_interface.go @@ -436,7 +436,7 @@ func (d *DevicePhysicalInterfaceDataSource) Read(ctx context.Context, req dataso offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_device_physical_interface_test.go b/internal/provider/data_source_fmc_device_physical_interface_test.go index 944f9945..fd9daf0f 100644 --- a/internal/provider/data_source_fmc_device_physical_interface_test.go +++ b/internal/provider/data_source_fmc_device_physical_interface_test.go @@ -112,8 +112,8 @@ func testAccNamedDataSourceFmcDevicePhysicalInterfaceConfig() string { config += ` data "fmc_device_physical_interface" "test" { - name = fmc_device_physical_interface.test.name device_id = var.device_id + name = fmc_device_physical_interface.test.name } ` return config diff --git a/internal/provider/data_source_fmc_device_subinterface.go b/internal/provider/data_source_fmc_device_subinterface.go index 0547a0c3..454bc401 100644 --- a/internal/provider/data_source_fmc_device_subinterface.go +++ b/internal/provider/data_source_fmc_device_subinterface.go @@ -118,7 +118,6 @@ func (d *DeviceSubinterfaceDataSource) Schema(ctx context.Context, req datasourc }, "interface_name": schema.StringAttribute{ MarkdownDescription: "Name of the parent interface (fmc_device_physical_interface.example.name).", - Optional: true, Computed: true, }, "sub_interface_id": schema.Int64Attribute{ diff --git a/internal/provider/data_source_fmc_device_subinterface_test.go b/internal/provider/data_source_fmc_device_subinterface_test.go index e53183fb..de5c2de1 100644 --- a/internal/provider/data_source_fmc_device_subinterface_test.go +++ b/internal/provider/data_source_fmc_device_subinterface_test.go @@ -126,8 +126,8 @@ func testAccNamedDataSourceFmcDeviceSubinterfaceConfig() string { config += ` data "fmc_device_subinterface" "test" { - name = fmc_device_subinterface.test.name device_id = var.device_id + name = fmc_device_subinterface.test.name } ` return config diff --git a/internal/provider/data_source_fmc_device_vrf.go b/internal/provider/data_source_fmc_device_vrf.go index cd98ffff..9727857b 100644 --- a/internal/provider/data_source_fmc_device_vrf.go +++ b/internal/provider/data_source_fmc_device_vrf.go @@ -152,7 +152,7 @@ func (d *DeviceVRFDataSource) Read(ctx context.Context, req datasource.ReadReque offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_device_vrf_test.go b/internal/provider/data_source_fmc_device_vrf_test.go index 34b9277a..b09cb8b1 100644 --- a/internal/provider/data_source_fmc_device_vrf_test.go +++ b/internal/provider/data_source_fmc_device_vrf_test.go @@ -110,8 +110,8 @@ func testAccNamedDataSourceFmcDeviceVRFConfig() string { config += ` data "fmc_device_vrf" "test" { - name = fmc_device_vrf.test.name device_id = var.device_id + name = fmc_device_vrf.test.name } ` return config diff --git a/internal/provider/data_source_fmc_extended_acl.go b/internal/provider/data_source_fmc_extended_acl.go index 64d748f9..989a69c2 100644 --- a/internal/provider/data_source_fmc_extended_acl.go +++ b/internal/provider/data_source_fmc_extended_acl.go @@ -228,7 +228,7 @@ func (d *ExtendedACLDataSource) Read(ctx context.Context, req datasource.ReadReq offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_fqdn_object.go b/internal/provider/data_source_fmc_fqdn_object.go index f5037170..d4e308f1 100644 --- a/internal/provider/data_source_fmc_fqdn_object.go +++ b/internal/provider/data_source_fmc_fqdn_object.go @@ -136,7 +136,7 @@ func (d *FQDNObjectDataSource) Read(ctx context.Context, req datasource.ReadRequ offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_host.go b/internal/provider/data_source_fmc_host.go index f09bc87e..046f514c 100644 --- a/internal/provider/data_source_fmc_host.go +++ b/internal/provider/data_source_fmc_host.go @@ -136,7 +136,7 @@ func (d *HostDataSource) Read(ctx context.Context, req datasource.ReadRequest, r offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_icmpv4_object.go b/internal/provider/data_source_fmc_icmpv4_object.go index d7487ab2..f20496c6 100644 --- a/internal/provider/data_source_fmc_icmpv4_object.go +++ b/internal/provider/data_source_fmc_icmpv4_object.go @@ -140,7 +140,7 @@ func (d *ICMPv4ObjectDataSource) Read(ctx context.Context, req datasource.ReadRe offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_icmpv6_object.go b/internal/provider/data_source_fmc_icmpv6_object.go index 7ad1dbaa..7245bac7 100644 --- a/internal/provider/data_source_fmc_icmpv6_object.go +++ b/internal/provider/data_source_fmc_icmpv6_object.go @@ -136,7 +136,7 @@ func (d *ICMPv6ObjectDataSource) Read(ctx context.Context, req datasource.ReadRe offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_interface_group.go b/internal/provider/data_source_fmc_interface_group.go index eee9bf1d..92563e61 100644 --- a/internal/provider/data_source_fmc_interface_group.go +++ b/internal/provider/data_source_fmc_interface_group.go @@ -136,7 +136,7 @@ func (d *InterfaceGroupDataSource) Read(ctx context.Context, req datasource.Read offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_intrusion_policy.go b/internal/provider/data_source_fmc_intrusion_policy.go index 06e0dda0..f6b1f9ee 100644 --- a/internal/provider/data_source_fmc_intrusion_policy.go +++ b/internal/provider/data_source_fmc_intrusion_policy.go @@ -132,7 +132,7 @@ func (d *IntrusionPolicyDataSource) Read(ctx context.Context, req datasource.Rea offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_network.go b/internal/provider/data_source_fmc_network.go index 9fb6716e..d55782e5 100644 --- a/internal/provider/data_source_fmc_network.go +++ b/internal/provider/data_source_fmc_network.go @@ -136,7 +136,7 @@ func (d *NetworkDataSource) Read(ctx context.Context, req datasource.ReadRequest offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_network_analysis_policy.go b/internal/provider/data_source_fmc_network_analysis_policy.go index 68cc8a45..9def5b24 100644 --- a/internal/provider/data_source_fmc_network_analysis_policy.go +++ b/internal/provider/data_source_fmc_network_analysis_policy.go @@ -132,7 +132,7 @@ func (d *NetworkAnalysisPolicyDataSource) Read(ctx context.Context, req datasour offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_port.go b/internal/provider/data_source_fmc_port.go index 476ab8f3..cd8f2857 100644 --- a/internal/provider/data_source_fmc_port.go +++ b/internal/provider/data_source_fmc_port.go @@ -136,7 +136,7 @@ func (d *PortDataSource) Read(ctx context.Context, req datasource.ReadRequest, r offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_port_group.go b/internal/provider/data_source_fmc_port_group.go index f237e6b7..ee326a50 100644 --- a/internal/provider/data_source_fmc_port_group.go +++ b/internal/provider/data_source_fmc_port_group.go @@ -148,7 +148,7 @@ func (d *PortGroupDataSource) Read(ctx context.Context, req datasource.ReadReque offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_range.go b/internal/provider/data_source_fmc_range.go index 708d7c88..9c3229b2 100644 --- a/internal/provider/data_source_fmc_range.go +++ b/internal/provider/data_source_fmc_range.go @@ -132,7 +132,7 @@ func (d *RangeDataSource) Read(ctx context.Context, req datasource.ReadRequest, offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_security_zone.go b/internal/provider/data_source_fmc_security_zone.go index b0a85143..eab4eb3e 100644 --- a/internal/provider/data_source_fmc_security_zone.go +++ b/internal/provider/data_source_fmc_security_zone.go @@ -75,7 +75,7 @@ func (d *SecurityZoneDataSource) Schema(ctx context.Context, req datasource.Sche Optional: true, Computed: true, }, - "interface_mode": schema.StringAttribute{ + "interface_type": schema.StringAttribute{ MarkdownDescription: "The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces.", Computed: true, }, @@ -128,7 +128,7 @@ func (d *SecurityZoneDataSource) Read(ctx context.Context, req datasource.ReadRe offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_security_zone_test.go b/internal/provider/data_source_fmc_security_zone_test.go index e40d04ab..abeebff9 100644 --- a/internal/provider/data_source_fmc_security_zone_test.go +++ b/internal/provider/data_source_fmc_security_zone_test.go @@ -31,7 +31,7 @@ import ( func TestAccDataSourceFmcSecurityZone(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("data.fmc_security_zone.test", "name", "security_zone_1")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_security_zone.test", "interface_mode", "ROUTED")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_security_zone.test", "interface_type", "ROUTED")) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -59,7 +59,7 @@ func TestAccDataSourceFmcSecurityZone(t *testing.T) { func testAccDataSourceFmcSecurityZoneConfig() string { config := `resource "fmc_security_zone" "test" {` + "\n" config += ` name = "security_zone_1"` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += `}` + "\n" config += ` @@ -73,7 +73,7 @@ func testAccDataSourceFmcSecurityZoneConfig() string { func testAccNamedDataSourceFmcSecurityZoneConfig() string { config := `resource "fmc_security_zone" "test" {` + "\n" config += ` name = "security_zone_1"` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += `}` + "\n" config += ` diff --git a/internal/provider/data_source_fmc_security_zones.go b/internal/provider/data_source_fmc_security_zones.go index af585607..70ba792c 100644 --- a/internal/provider/data_source_fmc_security_zones.go +++ b/internal/provider/data_source_fmc_security_zones.go @@ -74,7 +74,7 @@ func (d *SecurityZonesDataSource) Schema(ctx context.Context, req datasource.Sch MarkdownDescription: "UUID of the managed Security Zone.", Computed: true, }, - "interface_mode": schema.StringAttribute{ + "interface_type": schema.StringAttribute{ MarkdownDescription: "The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces.", Computed: true, }, diff --git a/internal/provider/data_source_fmc_security_zones_test.go b/internal/provider/data_source_fmc_security_zones_test.go index a421b59c..55b7708d 100644 --- a/internal/provider/data_source_fmc_security_zones_test.go +++ b/internal/provider/data_source_fmc_security_zones_test.go @@ -31,7 +31,7 @@ import ( func TestAccDataSourceFmcSecurityZones(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttrSet("data.fmc_security_zones.test", "items.security_zone_1.id")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_security_zones.test", "items.security_zone_1.interface_mode", "ROUTED")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_security_zones.test", "items.security_zone_1.interface_type", "ROUTED")) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -55,7 +55,7 @@ func TestAccDataSourceFmcSecurityZones(t *testing.T) { func testAccDataSourceFmcSecurityZonesConfig() string { config := `resource "fmc_security_zones" "test" {` + "\n" config += ` items = { "security_zone_1" = {` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += ` }}` + "\n" config += `}` + "\n" diff --git a/internal/provider/data_source_fmc_sgt.go b/internal/provider/data_source_fmc_sgt.go index b0d16268..cc6425b1 100644 --- a/internal/provider/data_source_fmc_sgt.go +++ b/internal/provider/data_source_fmc_sgt.go @@ -132,7 +132,7 @@ func (d *SGTDataSource) Read(ctx context.Context, req datasource.ReadRequest, re offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_snmp_alert.go b/internal/provider/data_source_fmc_snmp_alert.go index 005b2a35..4c0be5f9 100644 --- a/internal/provider/data_source_fmc_snmp_alert.go +++ b/internal/provider/data_source_fmc_snmp_alert.go @@ -124,7 +124,7 @@ func (d *SNMPAlertDataSource) Read(ctx context.Context, req datasource.ReadReque offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_standard_acl.go b/internal/provider/data_source_fmc_standard_acl.go index 7d342590..9a337777 100644 --- a/internal/provider/data_source_fmc_standard_acl.go +++ b/internal/provider/data_source_fmc_standard_acl.go @@ -164,7 +164,7 @@ func (d *StandardACLDataSource) Read(ctx context.Context, req datasource.ReadReq offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_syslog_alert.go b/internal/provider/data_source_fmc_syslog_alert.go index 63ae174c..c66d9003 100644 --- a/internal/provider/data_source_fmc_syslog_alert.go +++ b/internal/provider/data_source_fmc_syslog_alert.go @@ -124,7 +124,7 @@ func (d *SyslogAlertDataSource) Read(ctx context.Context, req datasource.ReadReq offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_url.go b/internal/provider/data_source_fmc_url.go index 099ec2d3..7923db25 100644 --- a/internal/provider/data_source_fmc_url.go +++ b/internal/provider/data_source_fmc_url.go @@ -132,7 +132,7 @@ func (d *URLDataSource) Read(ctx context.Context, req datasource.ReadRequest, re offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_url_group.go b/internal/provider/data_source_fmc_url_group.go index bde66899..f5467138 100644 --- a/internal/provider/data_source_fmc_url_group.go +++ b/internal/provider/data_source_fmc_url_group.go @@ -152,7 +152,7 @@ func (d *URLGroupDataSource) Read(ctx context.Context, req datasource.ReadReques offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_variable_set.go b/internal/provider/data_source_fmc_variable_set.go index 657a7fb8..400a4b7f 100644 --- a/internal/provider/data_source_fmc_variable_set.go +++ b/internal/provider/data_source_fmc_variable_set.go @@ -128,7 +128,7 @@ func (d *VariableSetDataSource) Read(ctx context.Context, req datasource.ReadReq offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_vlan_tag.go b/internal/provider/data_source_fmc_vlan_tag.go index c7b9943b..03cb48db 100644 --- a/internal/provider/data_source_fmc_vlan_tag.go +++ b/internal/provider/data_source_fmc_vlan_tag.go @@ -136,7 +136,7 @@ func (d *VLANTagDataSource) Read(ctx context.Context, req datasource.ReadRequest offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/data_source_fmc_vlan_tag_group.go b/internal/provider/data_source_fmc_vlan_tag_group.go index 1f7d19ea..19c436bc 100644 --- a/internal/provider/data_source_fmc_vlan_tag_group.go +++ b/internal/provider/data_source_fmc_vlan_tag_group.go @@ -156,7 +156,7 @@ func (d *VLANTagGroupDataSource) Read(ctx context.Context, req datasource.ReadRe offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := d.client.Get(config.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/model_fmc_bfd_template.go b/internal/provider/model_fmc_bfd_template.go new file mode 100644 index 00000000..1cab1185 --- /dev/null +++ b/internal/provider/model_fmc_bfd_template.go @@ -0,0 +1,251 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type BFDTemplate struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + HopType types.String `tfsdk:"hop_type"` + Echo types.String `tfsdk:"echo"` + IntervalTime types.String `tfsdk:"interval_time"` + MinTransmit types.Int64 `tfsdk:"min_transmit"` + TxRxMultiplier types.Int64 `tfsdk:"tx_rx_multiplier"` + MinReceive types.Int64 `tfsdk:"min_receive"` + AuthenticationPassword types.String `tfsdk:"authentication_password"` + AuthenticationKeyId types.Int64 `tfsdk:"authentication_key_id"` + AuthenticationType types.String `tfsdk:"authentication_type"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data BFDTemplate) getPath() string { + return "/api/fmc_config/v1/domain/{DOMAIN_UUID}/object/bfdtemplates" +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data BFDTemplate) toBody(ctx context.Context, state BFDTemplate) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.Name.IsNull() { + body, _ = sjson.Set(body, "name", data.Name.ValueString()) + } + if !data.HopType.IsNull() { + body, _ = sjson.Set(body, "hopType", data.HopType.ValueString()) + } + if !data.Echo.IsNull() { + body, _ = sjson.Set(body, "echo", data.Echo.ValueString()) + } + if !data.IntervalTime.IsNull() { + body, _ = sjson.Set(body, "txRxInterval", data.IntervalTime.ValueString()) + } + if !data.MinTransmit.IsNull() { + body, _ = sjson.Set(body, "minTransmit", data.MinTransmit.ValueInt64()) + } + if !data.TxRxMultiplier.IsNull() { + body, _ = sjson.Set(body, "txRxMultiplier", data.TxRxMultiplier.ValueInt64()) + } + if !data.MinReceive.IsNull() { + body, _ = sjson.Set(body, "minReceive", data.MinReceive.ValueInt64()) + } + if !data.AuthenticationPassword.IsNull() { + body, _ = sjson.Set(body, "authentication.authKey", data.AuthenticationPassword.ValueString()) + } + if !data.AuthenticationKeyId.IsNull() { + body, _ = sjson.Set(body, "authentication.authKeyId", data.AuthenticationKeyId.ValueInt64()) + } + if !data.AuthenticationType.IsNull() { + body, _ = sjson.Set(body, "authentication.authType", data.AuthenticationType.ValueString()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *BFDTemplate) 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("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("echo"); value.Exists() { + data.Echo = types.StringValue(value.String()) + } else { + data.Echo = types.StringNull() + } + if value := res.Get("txRxInterval"); value.Exists() { + data.IntervalTime = types.StringValue(value.String()) + } else { + data.IntervalTime = types.StringNull() + } + if value := res.Get("minTransmit"); value.Exists() { + data.MinTransmit = types.Int64Value(value.Int()) + } else { + data.MinTransmit = types.Int64Null() + } + if value := res.Get("txRxMultiplier"); value.Exists() { + data.TxRxMultiplier = types.Int64Value(value.Int()) + } else { + data.TxRxMultiplier = types.Int64Null() + } + if value := res.Get("minReceive"); value.Exists() { + data.MinReceive = types.Int64Value(value.Int()) + } else { + data.MinReceive = types.Int64Null() + } + if value := res.Get("authentication.authKey"); value.Exists() { + data.AuthenticationPassword = types.StringValue(value.String()) + } else { + data.AuthenticationPassword = types.StringNull() + } + if value := res.Get("authentication.authKeyId"); value.Exists() { + data.AuthenticationKeyId = types.Int64Value(value.Int()) + } else { + data.AuthenticationKeyId = types.Int64Null() + } + if value := res.Get("authentication.authType"); value.Exists() { + data.AuthenticationType = types.StringValue(value.String()) + } else { + data.AuthenticationType = types.StringNull() + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *BFDTemplate) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() && !data.HopType.IsNull() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("echo"); value.Exists() && !data.Echo.IsNull() { + data.Echo = types.StringValue(value.String()) + } else { + data.Echo = types.StringNull() + } + if value := res.Get("txRxInterval"); value.Exists() && !data.IntervalTime.IsNull() { + data.IntervalTime = types.StringValue(value.String()) + } else { + data.IntervalTime = types.StringNull() + } + if value := res.Get("minTransmit"); value.Exists() && !data.MinTransmit.IsNull() { + data.MinTransmit = types.Int64Value(value.Int()) + } else { + data.MinTransmit = types.Int64Null() + } + if value := res.Get("txRxMultiplier"); value.Exists() && !data.TxRxMultiplier.IsNull() { + data.TxRxMultiplier = types.Int64Value(value.Int()) + } else { + data.TxRxMultiplier = types.Int64Null() + } + if value := res.Get("minReceive"); value.Exists() && !data.MinReceive.IsNull() { + data.MinReceive = types.Int64Value(value.Int()) + } else { + data.MinReceive = types.Int64Null() + } + if value := res.Get("authentication.authKey"); value.Exists() && !data.AuthenticationPassword.IsNull() { + data.AuthenticationPassword = types.StringValue(value.String()) + } else { + data.AuthenticationPassword = types.StringNull() + } + if value := res.Get("authentication.authKeyId"); value.Exists() && !data.AuthenticationKeyId.IsNull() { + data.AuthenticationKeyId = types.Int64Value(value.Int()) + } else { + data.AuthenticationKeyId = types.Int64Null() + } + if value := res.Get("authentication.authType"); value.Exists() && !data.AuthenticationType.IsNull() { + data.AuthenticationType = types.StringValue(value.String()) + } else { + data.AuthenticationType = types.StringNull() + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *BFDTemplate) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_bgd_template.go b/internal/provider/model_fmc_bgd_template.go new file mode 100644 index 00000000..eac1b752 --- /dev/null +++ b/internal/provider/model_fmc_bgd_template.go @@ -0,0 +1,209 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type BGDTemplate struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + HopType types.String `tfsdk:"hop_type"` + Echo types.String `tfsdk:"echo"` + IntervalTime types.String `tfsdk:"interval_time"` + MinTransmit types.Int64 `tfsdk:"min_transmit"` + TxRxMultiplier types.Int64 `tfsdk:"tx_rx_multiplier"` + MinReceive types.Int64 `tfsdk:"min_receive"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data BGDTemplate) getPath() string { + return "/api/fmc_config/v1/domain/{DOMAIN_UUID}/object/bfdtemplates" +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data BGDTemplate) toBody(ctx context.Context, state BGDTemplate) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.Name.IsNull() { + body, _ = sjson.Set(body, "name", data.Name.ValueString()) + } + if !data.HopType.IsNull() { + body, _ = sjson.Set(body, "hopType", data.HopType.ValueString()) + } + if !data.Echo.IsNull() { + body, _ = sjson.Set(body, "echo", data.Echo.ValueString()) + } + if !data.IntervalTime.IsNull() { + body, _ = sjson.Set(body, "txRxInterval", data.IntervalTime.ValueString()) + } + if !data.MinTransmit.IsNull() { + body, _ = sjson.Set(body, "minTransmit", data.MinTransmit.ValueInt64()) + } + if !data.TxRxMultiplier.IsNull() { + body, _ = sjson.Set(body, "txRxMultiplier", data.TxRxMultiplier.ValueInt64()) + } + if !data.MinReceive.IsNull() { + body, _ = sjson.Set(body, "minReceive", data.MinReceive.ValueInt64()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *BGDTemplate) 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("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("echo"); value.Exists() { + data.Echo = types.StringValue(value.String()) + } else { + data.Echo = types.StringNull() + } + if value := res.Get("txRxInterval"); value.Exists() { + data.IntervalTime = types.StringValue(value.String()) + } else { + data.IntervalTime = types.StringNull() + } + if value := res.Get("minTransmit"); value.Exists() { + data.MinTransmit = types.Int64Value(value.Int()) + } else { + data.MinTransmit = types.Int64Value(100000) + } + if value := res.Get("txRxMultiplier"); value.Exists() { + data.TxRxMultiplier = types.Int64Value(value.Int()) + } else { + data.TxRxMultiplier = types.Int64Value(3) + } + if value := res.Get("minReceive"); value.Exists() { + data.MinReceive = types.Int64Value(value.Int()) + } else { + data.MinReceive = types.Int64Value(100000) + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *BGDTemplate) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() && !data.HopType.IsNull() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("echo"); value.Exists() && !data.Echo.IsNull() { + data.Echo = types.StringValue(value.String()) + } else { + data.Echo = types.StringNull() + } + if value := res.Get("txRxInterval"); value.Exists() && !data.IntervalTime.IsNull() { + data.IntervalTime = types.StringValue(value.String()) + } else { + data.IntervalTime = types.StringNull() + } + if value := res.Get("minTransmit"); value.Exists() && !data.MinTransmit.IsNull() { + data.MinTransmit = types.Int64Value(value.Int()) + } else if data.MinTransmit.ValueInt64() != 100000 { + data.MinTransmit = types.Int64Null() + } + if value := res.Get("txRxMultiplier"); value.Exists() && !data.TxRxMultiplier.IsNull() { + data.TxRxMultiplier = types.Int64Value(value.Int()) + } else if data.TxRxMultiplier.ValueInt64() != 3 { + data.TxRxMultiplier = types.Int64Null() + } + if value := res.Get("minReceive"); value.Exists() && !data.MinReceive.IsNull() { + data.MinReceive = types.Int64Value(value.Int()) + } else if data.MinReceive.ValueInt64() != 100000 { + data.MinReceive = types.Int64Null() + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *BGDTemplate) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_device_bfd.go b/internal/provider/model_fmc_device_bfd.go new file mode 100644 index 00000000..7f443915 --- /dev/null +++ b/internal/provider/model_fmc_device_bfd.go @@ -0,0 +1,212 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type DeviceBFD struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + DeviceId types.String `tfsdk:"device_id"` + Type types.String `tfsdk:"type"` + HopType types.String `tfsdk:"hop_type"` + BfdTemplateId types.String `tfsdk:"bfd_template_id"` + InterfaceLogicalName types.String `tfsdk:"interface_logical_name"` + DestinationHostObjectId types.String `tfsdk:"destination_host_object_id"` + SourceHostObjectId types.String `tfsdk:"source_host_object_id"` + InterfaceId types.String `tfsdk:"interface_id"` + SlowTimer types.Int64 `tfsdk:"slow_timer"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceBFD) getPath() string { + return fmt.Sprintf("/api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bfdpolicies", url.QueryEscape(data.DeviceId.ValueString())) +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceBFD) toBody(ctx context.Context, state DeviceBFD) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.HopType.IsNull() { + body, _ = sjson.Set(body, "hopType", data.HopType.ValueString()) + } + if !data.BfdTemplateId.IsNull() { + body, _ = sjson.Set(body, "template.id", data.BfdTemplateId.ValueString()) + } + if !data.InterfaceLogicalName.IsNull() { + body, _ = sjson.Set(body, "interface.ifname", data.InterfaceLogicalName.ValueString()) + } + if !data.DestinationHostObjectId.IsNull() { + body, _ = sjson.Set(body, "destinationAddress.id", data.DestinationHostObjectId.ValueString()) + } + if !data.SourceHostObjectId.IsNull() { + body, _ = sjson.Set(body, "sourceAddress.id", data.SourceHostObjectId.ValueString()) + } + if !data.InterfaceId.IsNull() { + body, _ = sjson.Set(body, "interface.id", data.InterfaceId.ValueString()) + } + if !data.SlowTimer.IsNull() { + body, _ = sjson.Set(body, "slowTimer", data.SlowTimer.ValueInt64()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceBFD) fromBody(ctx context.Context, res gjson.Result) { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("template.id"); value.Exists() { + data.BfdTemplateId = types.StringValue(value.String()) + } else { + data.BfdTemplateId = types.StringNull() + } + if value := res.Get("interface.ifname"); value.Exists() { + data.InterfaceLogicalName = types.StringValue(value.String()) + } else { + data.InterfaceLogicalName = types.StringNull() + } + if value := res.Get("destinationAddress.id"); value.Exists() { + data.DestinationHostObjectId = types.StringValue(value.String()) + } else { + data.DestinationHostObjectId = types.StringNull() + } + if value := res.Get("sourceAddress.id"); value.Exists() { + data.SourceHostObjectId = types.StringValue(value.String()) + } else { + data.SourceHostObjectId = types.StringNull() + } + if value := res.Get("interface.id"); value.Exists() { + data.InterfaceId = types.StringValue(value.String()) + } else { + data.InterfaceId = types.StringNull() + } + if value := res.Get("slowTimer"); value.Exists() { + data.SlowTimer = types.Int64Value(value.Int()) + } else { + data.SlowTimer = types.Int64Value(1000) + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *DeviceBFD) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("hopType"); value.Exists() && !data.HopType.IsNull() { + data.HopType = types.StringValue(value.String()) + } else { + data.HopType = types.StringNull() + } + if value := res.Get("template.id"); value.Exists() && !data.BfdTemplateId.IsNull() { + data.BfdTemplateId = types.StringValue(value.String()) + } else { + data.BfdTemplateId = types.StringNull() + } + if value := res.Get("interface.ifname"); value.Exists() && !data.InterfaceLogicalName.IsNull() { + data.InterfaceLogicalName = types.StringValue(value.String()) + } else { + data.InterfaceLogicalName = types.StringNull() + } + if value := res.Get("destinationAddress.id"); value.Exists() && !data.DestinationHostObjectId.IsNull() { + data.DestinationHostObjectId = types.StringValue(value.String()) + } else { + data.DestinationHostObjectId = types.StringNull() + } + if value := res.Get("sourceAddress.id"); value.Exists() && !data.SourceHostObjectId.IsNull() { + data.SourceHostObjectId = types.StringValue(value.String()) + } else { + data.SourceHostObjectId = types.StringNull() + } + if value := res.Get("interface.id"); value.Exists() && !data.InterfaceId.IsNull() { + data.InterfaceId = types.StringValue(value.String()) + } else { + data.InterfaceId = types.StringNull() + } + if value := res.Get("slowTimer"); value.Exists() && !data.SlowTimer.IsNull() { + data.SlowTimer = types.Int64Value(value.Int()) + } else if data.SlowTimer.ValueInt64() != 1000 { + data.SlowTimer = types.Int64Null() + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *DeviceBFD) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_device_bgp.go b/internal/provider/model_fmc_device_bgp.go new file mode 100644 index 00000000..93d3150f --- /dev/null +++ b/internal/provider/model_fmc_device_bgp.go @@ -0,0 +1,1797 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "slices" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type DeviceBGP struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + DeviceId types.String `tfsdk:"device_id"` + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + AsNumber types.String `tfsdk:"as_number"` + Ipv4AddressFamilyType types.String `tfsdk:"ipv4_address_family_type"` + Ipv4LearnedRouteMapId types.String `tfsdk:"ipv4_learned_route_map_id"` + Ipv4DefaultInformationOrginate types.Bool `tfsdk:"ipv4_default_information_orginate"` + Ipv4AutoAummary types.Bool `tfsdk:"ipv4_auto_aummary"` + Ipv4BgpSupressInactive types.Bool `tfsdk:"ipv4_bgp_supress_inactive"` + Ipv4Synchronization types.Bool `tfsdk:"ipv4_synchronization"` + Ipv4BgpRedistributeInternal types.Bool `tfsdk:"ipv4_bgp_redistribute_internal"` + Ipv4ExternalDistance types.Int64 `tfsdk:"ipv4_external_distance"` + Ipv4InternalDistance types.Int64 `tfsdk:"ipv4_internal_distance"` + Ipv4LocalDistance types.Int64 `tfsdk:"ipv4_local_distance"` + Ipv4ForwardPacketsOverMultipathIbgp types.Int64 `tfsdk:"ipv4_forward_packets_over_multipath_ibgp"` + Ipv4ForwardPacketsOverMultipathEbgp types.Int64 `tfsdk:"ipv4_forward_packets_over_multipath_ebgp"` + Ipv4Neighbors []DeviceBGPIpv4Neighbors `tfsdk:"ipv4_neighbors"` + Ipv4AggregateAddresses []DeviceBGPIpv4AggregateAddresses `tfsdk:"ipv4_aggregate_addresses"` + Ipv4Filterings []DeviceBGPIpv4Filterings `tfsdk:"ipv4_filterings"` + Ipv4Networks []DeviceBGPIpv4Networks `tfsdk:"ipv4_networks"` + Ipv4Redistributions []DeviceBGPIpv4Redistributions `tfsdk:"ipv4_redistributions"` + Ipv4RouteInjections []DeviceBGPIpv4RouteInjections `tfsdk:"ipv4_route_injections"` +} + +type DeviceBGPIpv4Neighbors struct { + NeighborAddress types.String `tfsdk:"neighbor_address"` + NeighborRemoteAs types.String `tfsdk:"neighbor_remote_as"` + NeighborBfd types.String `tfsdk:"neighbor_bfd"` + UpdateSourceInterfaceId types.String `tfsdk:"update_source_interface_id"` + EnableAddressFamily types.Bool `tfsdk:"enable_address_family"` + NeighborShutdown types.Bool `tfsdk:"neighbor_shutdown"` + NeighborDescription types.String `tfsdk:"neighbor_description"` + NeighborFilterAccessLists []DeviceBGPIpv4NeighborsNeighborFilterAccessLists `tfsdk:"neighbor_filter_access_lists"` + NeighborFilterRouteMapLists []DeviceBGPIpv4NeighborsNeighborFilterRouteMapLists `tfsdk:"neighbor_filter_route_map_lists"` + NeighborFilterPrefixLists []DeviceBGPIpv4NeighborsNeighborFilterPrefixLists `tfsdk:"neighbor_filter_prefix_lists"` + NeighborFilterAsPathLists []DeviceBGPIpv4NeighborsNeighborFilterAsPathLists `tfsdk:"neighbor_filter_as_path_lists"` + NeighborFilterMaxPrefix types.Int64 `tfsdk:"neighbor_filter_max_prefix"` + NeighborFilterWarningOnly types.Bool `tfsdk:"neighbor_filter_warning_only"` + NeighborFilterThresholdValue types.Int64 `tfsdk:"neighbor_filter_threshold_value"` + NeighborFilterRestartInterval types.Int64 `tfsdk:"neighbor_filter_restart_interval"` + NeighborRoutesAdvertisementInterval types.Int64 `tfsdk:"neighbor_routes_advertisement_interval"` + NeighborRoutesRemovePrivateAs types.Bool `tfsdk:"neighbor_routes_remove_private_as"` + NeighborGenerateDefaultRouteMapId types.String `tfsdk:"neighbor_generate_default_route_map_id"` + NeighborRoutesAdvertiseMapUseExist types.Bool `tfsdk:"neighbor_routes_advertise_map_use_exist"` + NeighborRoutesAdvertiseMapId types.String `tfsdk:"neighbor_routes_advertise_map_id"` + NeighborRoutesAdvertiseExistNonexistMapId types.String `tfsdk:"neighbor_routes_advertise_exist_nonexist_map_id"` + NeighborKeepaliveInterval types.Int64 `tfsdk:"neighbor_keepalive_interval"` + NeighborHoldTime types.Int64 `tfsdk:"neighbor_hold_time"` + NeighborMinHoldTime types.Int64 `tfsdk:"neighbor_min_hold_time"` + NeighborAuthenticationPassword types.String `tfsdk:"neighbor_authentication_password"` + NeighborSendCommunityAttribute types.Bool `tfsdk:"neighbor_send_community_attribute"` + NeighborNexthopSelf types.Bool `tfsdk:"neighbor_nexthop_self"` + NeighborDisableConnectionVerification types.Bool `tfsdk:"neighbor_disable_connection_verification"` + NeighborTcpMtuPathDiscovery types.Bool `tfsdk:"neighbor_tcp_mtu_path_discovery"` + NeighborMaxHopCount types.Int64 `tfsdk:"neighbor_max_hop_count"` + NeighborTcpTransportMode types.Bool `tfsdk:"neighbor_tcp_transport_mode"` + NeighborWeight types.Int64 `tfsdk:"neighbor_weight"` + NeighborVersion types.String `tfsdk:"neighbor_version"` + NeighborCustomizedLocalAsNumber types.String `tfsdk:"neighbor_customized_local_as_number"` + NeighborCustomizedNoPrepend types.Bool `tfsdk:"neighbor_customized_no_prepend"` + NeighborCustomizedReplaceAs types.Bool `tfsdk:"neighbor_customized_replace_as"` + NeighborCustomizedAcceptBothAs types.Bool `tfsdk:"neighbor_customized_accept_both_as"` +} + +type DeviceBGPIpv4AggregateAddresses struct { + GenerateAs types.Bool `tfsdk:"generate_as"` + Filter types.Bool `tfsdk:"filter"` + NetworkId types.String `tfsdk:"network_id"` + AdvertiseMapId types.String `tfsdk:"advertise_map_id"` + AttributeMapId types.String `tfsdk:"attribute_map_id"` + SuppressMapId types.String `tfsdk:"suppress_map_id"` +} + +type DeviceBGPIpv4Filterings struct { + AccessListId types.String `tfsdk:"access_list_id"` + NetworkDirection types.String `tfsdk:"network_direction"` + Protocol types.String `tfsdk:"protocol"` + ProrocolProcess types.String `tfsdk:"prorocol_process"` +} + +type DeviceBGPIpv4Networks struct { + NetworkId types.String `tfsdk:"network_id"` + RouteMapId types.String `tfsdk:"route_map_id"` +} + +type DeviceBGPIpv4Redistributions struct { + SourceProtocol types.String `tfsdk:"source_protocol"` + RouteMapId types.String `tfsdk:"route_map_id"` + Metric types.Int64 `tfsdk:"metric"` + ProcessId types.String `tfsdk:"process_id"` + MatchExternal1 types.Bool `tfsdk:"match_external1"` + MatchExternal2 types.Bool `tfsdk:"match_external2"` + MatchInternal types.Bool `tfsdk:"match_internal"` + MatchNssaExternal1 types.Bool `tfsdk:"match_nssa_external1"` + MatchNssaExternal2 types.Bool `tfsdk:"match_nssa_external2"` +} + +type DeviceBGPIpv4RouteInjections struct { + InjectRouteMapId types.String `tfsdk:"inject_route_map_id"` + ExistRouteMapId types.String `tfsdk:"exist_route_map_id"` +} + +type DeviceBGPIpv4NeighborsNeighborFilterAccessLists struct { + AccessListId types.String `tfsdk:"access_list_id"` + UpdateDirection types.String `tfsdk:"update_direction"` +} +type DeviceBGPIpv4NeighborsNeighborFilterRouteMapLists struct { + RouteMapId types.String `tfsdk:"route_map_id"` + UpdateDirection types.String `tfsdk:"update_direction"` +} +type DeviceBGPIpv4NeighborsNeighborFilterPrefixLists struct { + PrefixListId types.String `tfsdk:"prefix_list_id"` + UpdateDirection types.String `tfsdk:"update_direction"` +} +type DeviceBGPIpv4NeighborsNeighborFilterAsPathLists struct { + UpdateDirection types.String `tfsdk:"update_direction"` + AsPathId types.String `tfsdk:"as_path_id"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceBGP) getPath() string { + return fmt.Sprintf("/api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bgp", url.QueryEscape(data.DeviceId.ValueString())) +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceBGP) toBody(ctx context.Context, state DeviceBGP) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.Ipv4LearnedRouteMapId.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.aftableMap.id", data.Ipv4LearnedRouteMapId.ValueString()) + } + if !data.Ipv4DefaultInformationOrginate.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.defaultInformationOrginate", data.Ipv4DefaultInformationOrginate.ValueBool()) + } + if !data.Ipv4AutoAummary.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.autoSummary", data.Ipv4AutoAummary.ValueBool()) + } + if !data.Ipv4BgpSupressInactive.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.bgpSupressInactive", data.Ipv4BgpSupressInactive.ValueBool()) + } + if !data.Ipv4Synchronization.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.synchronization", data.Ipv4Synchronization.ValueBool()) + } + if !data.Ipv4BgpRedistributeInternal.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.bgpRedistributeInternal", data.Ipv4BgpRedistributeInternal.ValueBool()) + } + if !data.Ipv4ExternalDistance.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.distance.externalDistance", data.Ipv4ExternalDistance.ValueInt64()) + } + if !data.Ipv4InternalDistance.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.distance.internalDistance", data.Ipv4InternalDistance.ValueInt64()) + } + if !data.Ipv4LocalDistance.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.distance.localDistance", data.Ipv4LocalDistance.ValueInt64()) + } + if !data.Ipv4ForwardPacketsOverMultipathIbgp.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.ibgp", data.Ipv4ForwardPacketsOverMultipathIbgp.ValueInt64()) + } + if !data.Ipv4ForwardPacketsOverMultipathEbgp.IsNull() { + body, _ = sjson.Set(body, "addressFamilyIPv4.ebgp", data.Ipv4ForwardPacketsOverMultipathEbgp.ValueInt64()) + } + if len(data.Ipv4Neighbors) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.neighbors", []interface{}{}) + for _, item := range data.Ipv4Neighbors { + itemBody := "" + if !item.NeighborAddress.IsNull() { + itemBody, _ = sjson.Set(itemBody, "ipv4Address", item.NeighborAddress.ValueString()) + } + if !item.NeighborRemoteAs.IsNull() { + itemBody, _ = sjson.Set(itemBody, "remoteAs", item.NeighborRemoteAs.ValueString()) + } + if !item.NeighborBfd.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborGeneral.fallOverBFD", item.NeighborBfd.ValueString()) + } + if !item.UpdateSourceInterfaceId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborGeneral.updateSource.id", item.UpdateSourceInterfaceId.ValueString()) + } + if !item.EnableAddressFamily.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborGeneral.enableAddress", item.EnableAddressFamily.ValueBool()) + } + if !item.NeighborShutdown.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborGeneral.shutdown", item.NeighborShutdown.ValueBool()) + } + if !item.NeighborDescription.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborGeneral.description", item.NeighborDescription.ValueString()) + } + if len(item.NeighborFilterAccessLists) > 0 { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborDistributeLists", []interface{}{}) + for _, childItem := range item.NeighborFilterAccessLists { + itemChildBody := "" + if !childItem.AccessListId.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "accessList.id", childItem.AccessListId.ValueString()) + } + if !childItem.UpdateDirection.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "filterUpdateAction", childItem.UpdateDirection.ValueString()) + } + itemBody, _ = sjson.SetRaw(itemBody, "neighborFiltering.neighborDistributeLists.-1", itemChildBody) + } + } + if len(item.NeighborFilterRouteMapLists) > 0 { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborRouteMap", []interface{}{}) + for _, childItem := range item.NeighborFilterRouteMapLists { + itemChildBody := "" + if !childItem.RouteMapId.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "RouteMap.id", childItem.RouteMapId.ValueString()) + } + if !childItem.UpdateDirection.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "filterUpdateAction", childItem.UpdateDirection.ValueString()) + } + itemBody, _ = sjson.SetRaw(itemBody, "neighborFiltering.neighborRouteMap.-1", itemChildBody) + } + } + if len(item.NeighborFilterPrefixLists) > 0 { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.ipv4PrefixListFilter", []interface{}{}) + for _, childItem := range item.NeighborFilterPrefixLists { + itemChildBody := "" + if !childItem.PrefixListId.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "ipv4PrefixList.id", childItem.PrefixListId.ValueString()) + } + if !childItem.UpdateDirection.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "filterUpdateAction", childItem.UpdateDirection.ValueString()) + } + itemBody, _ = sjson.SetRaw(itemBody, "neighborFiltering.ipv4PrefixListFilter.-1", itemChildBody) + } + } + if len(item.NeighborFilterAsPathLists) > 0 { + itemBody, _ = sjson.Set(itemBody, "neighborFilterList.neighborFilterList", []interface{}{}) + for _, childItem := range item.NeighborFilterAsPathLists { + itemChildBody := "" + if !childItem.UpdateDirection.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "filterUpdateAction", childItem.UpdateDirection.ValueString()) + } + if !childItem.AsPathId.IsNull() { + itemChildBody, _ = sjson.Set(itemChildBody, "asPathList.id", childItem.AsPathId.ValueString()) + } + itemBody, _ = sjson.SetRaw(itemBody, "neighborFilterList.neighborFilterList.-1", itemChildBody) + } + } + if !item.NeighborFilterMaxPrefix.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborMaximumPrefix.maxPrefixLimit", item.NeighborFilterMaxPrefix.ValueInt64()) + } + if !item.NeighborFilterWarningOnly.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborMaximumPrefix.warningOnly", item.NeighborFilterWarningOnly.ValueBool()) + } + if !item.NeighborFilterThresholdValue.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborMaximumPrefix.thresholdValue", item.NeighborFilterThresholdValue.ValueInt64()) + } + if !item.NeighborFilterRestartInterval.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborMaximumPrefix.restartInterval", item.NeighborFilterRestartInterval.ValueInt64()) + } + if !item.NeighborRoutesAdvertisementInterval.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborRoutes.advertisementInterval", item.NeighborRoutesAdvertisementInterval.ValueInt64()) + } + if !item.NeighborRoutesRemovePrivateAs.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborRoutes.removePrivateAs", item.NeighborRoutesRemovePrivateAs.ValueBool()) + } + if !item.NeighborGenerateDefaultRouteMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborFiltering.neighborDefaultOriginate.routeMap.id", item.NeighborGenerateDefaultRouteMapId.ValueString()) + } + if !item.NeighborRoutesAdvertiseMapUseExist.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborRoutes.neighborAdvertiseMaps.existMap", item.NeighborRoutesAdvertiseMapUseExist.ValueBool()) + } + if !item.NeighborRoutesAdvertiseMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborRoutes.neighborAdvertiseMaps.routeMap.id", item.NeighborRoutesAdvertiseMapId.ValueString()) + } + if !item.NeighborRoutesAdvertiseExistNonexistMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborRoutes.neighborAdvertiseMaps.existRouteMap.id", item.NeighborRoutesAdvertiseExistNonexistMapId.ValueString()) + } + if !item.NeighborKeepaliveInterval.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborTimers.keepAliveInterval", item.NeighborKeepaliveInterval.ValueInt64()) + } + if !item.NeighborHoldTime.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborTimers.holdTime", item.NeighborHoldTime.ValueInt64()) + } + if !item.NeighborMinHoldTime.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborTimers.minimumHoldTime", item.NeighborMinHoldTime.ValueInt64()) + } + if !item.NeighborAuthenticationPassword.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborSecret", item.NeighborAuthenticationPassword.ValueString()) + } + if !item.NeighborSendCommunityAttribute.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.sendCommunity", item.NeighborSendCommunityAttribute.ValueBool()) + } + if !item.NeighborNexthopSelf.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.nextHopSelf", item.NeighborNexthopSelf.ValueBool()) + } + if !item.NeighborDisableConnectionVerification.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborHops.disableConnectedCheck", item.NeighborDisableConnectionVerification.ValueBool()) + } + if !item.NeighborTcpMtuPathDiscovery.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborTransportPathMTUDiscovery.disable", item.NeighborTcpMtuPathDiscovery.ValueBool()) + } + if !item.NeighborMaxHopCount.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborHops.maxHopCount", item.NeighborMaxHopCount.ValueInt64()) + } + if !item.NeighborTcpTransportMode.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborTransportConnectionMode.establishTCPSession", item.NeighborTcpTransportMode.ValueBool()) + } + if !item.NeighborWeight.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborWeight", item.NeighborWeight.ValueInt64()) + } + if !item.NeighborVersion.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborAdvanced.neighborVersion", item.NeighborVersion.ValueString()) + } + if !item.NeighborCustomizedLocalAsNumber.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborLocalAs.asNumber", item.NeighborCustomizedLocalAsNumber.ValueString()) + } + if !item.NeighborCustomizedNoPrepend.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborLocalAs.noPrepend", item.NeighborCustomizedNoPrepend.ValueBool()) + } + if !item.NeighborCustomizedReplaceAs.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborLocalAs.replaceAs", item.NeighborCustomizedReplaceAs.ValueBool()) + } + if !item.NeighborCustomizedAcceptBothAs.IsNull() { + itemBody, _ = sjson.Set(itemBody, "neighborLocalAs.dualAs", item.NeighborCustomizedAcceptBothAs.ValueBool()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.neighbors.-1", itemBody) + } + } + if len(data.Ipv4AggregateAddresses) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.aggregateAddressesIPv4s", []interface{}{}) + for _, item := range data.Ipv4AggregateAddresses { + itemBody := "" + if !item.GenerateAs.IsNull() { + itemBody, _ = sjson.Set(itemBody, "asSet", item.GenerateAs.ValueBool()) + } + if !item.Filter.IsNull() { + itemBody, _ = sjson.Set(itemBody, "summaryOnly", item.Filter.ValueBool()) + } + if !item.NetworkId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "ipv4AggregateNetwork.id", item.NetworkId.ValueString()) + } + if !item.AdvertiseMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "advertiseMap.id", item.AdvertiseMapId.ValueString()) + } + if !item.AttributeMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "attributeMap.id", item.AttributeMapId.ValueString()) + } + if !item.SuppressMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "suppressMap.id", item.SuppressMapId.ValueString()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.aggregateAddressesIPv4s.-1", itemBody) + } + } + if len(data.Ipv4Filterings) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.distributeLists", []interface{}{}) + for _, item := range data.Ipv4Filterings { + itemBody := "" + if !item.AccessListId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "ipv4AggregateNetwork.id", item.AccessListId.ValueString()) + } + if !item.NetworkDirection.IsNull() { + itemBody, _ = sjson.Set(itemBody, "type", item.NetworkDirection.ValueString()) + } + if !item.Protocol.IsNull() { + itemBody, _ = sjson.Set(itemBody, "protocol.protocol", item.Protocol.ValueString()) + } + if !item.ProrocolProcess.IsNull() { + itemBody, _ = sjson.Set(itemBody, "protocol.processId", item.ProrocolProcess.ValueString()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.distributeLists.-1", itemBody) + } + } + if len(data.Ipv4Networks) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.networks", []interface{}{}) + for _, item := range data.Ipv4Networks { + itemBody := "" + if !item.NetworkId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "ipv4Address.id", item.NetworkId.ValueString()) + } + if !item.RouteMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "routeMap.id", item.RouteMapId.ValueString()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.networks.-1", itemBody) + } + } + if len(data.Ipv4Redistributions) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.redistributeProtocols", []interface{}{}) + for _, item := range data.Ipv4Redistributions { + itemBody := "" + if !item.SourceProtocol.IsNull() { + itemBody, _ = sjson.Set(itemBody, "type", item.SourceProtocol.ValueString()) + } + if !item.RouteMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "routeMap.id", item.RouteMapId.ValueString()) + } + if !item.Metric.IsNull() { + itemBody, _ = sjson.Set(itemBody, "routeMetric.metricValue", item.Metric.ValueInt64()) + } + if !item.ProcessId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "processId", item.ProcessId.ValueString()) + } + if !item.MatchExternal1.IsNull() { + itemBody, _ = sjson.Set(itemBody, "matchExternal1", item.MatchExternal1.ValueBool()) + } + if !item.MatchExternal2.IsNull() { + itemBody, _ = sjson.Set(itemBody, "matchExternal2", item.MatchExternal2.ValueBool()) + } + if !item.MatchInternal.IsNull() { + itemBody, _ = sjson.Set(itemBody, "matchInternal", item.MatchInternal.ValueBool()) + } + if !item.MatchNssaExternal1.IsNull() { + itemBody, _ = sjson.Set(itemBody, "matchNssaExternal1", item.MatchNssaExternal1.ValueBool()) + } + if !item.MatchNssaExternal2.IsNull() { + itemBody, _ = sjson.Set(itemBody, "matchNssaExternal2", item.MatchNssaExternal2.ValueBool()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.redistributeProtocols.-1", itemBody) + } + } + if len(data.Ipv4RouteInjections) > 0 { + body, _ = sjson.Set(body, "addressFamilyIPv4.injectMaps", []interface{}{}) + for _, item := range data.Ipv4RouteInjections { + itemBody := "" + if !item.InjectRouteMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "injectMap.routeMap.id", item.InjectRouteMapId.ValueString()) + } + if !item.ExistRouteMapId.IsNull() { + itemBody, _ = sjson.Set(itemBody, "existMap.routeMap.id", item.ExistRouteMapId.ValueString()) + } + body, _ = sjson.SetRaw(body, "addressFamilyIPv4.injectMaps.-1", itemBody) + } + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceBGP) 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("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("asNumber"); value.Exists() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.type"); value.Exists() { + data.Ipv4AddressFamilyType = types.StringValue(value.String()) + } else { + data.Ipv4AddressFamilyType = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.aftableMap.id"); value.Exists() { + data.Ipv4LearnedRouteMapId = types.StringValue(value.String()) + } else { + data.Ipv4LearnedRouteMapId = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.defaultInformationOrginate"); value.Exists() { + data.Ipv4DefaultInformationOrginate = types.BoolValue(value.Bool()) + } else { + data.Ipv4DefaultInformationOrginate = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.autoSummary"); value.Exists() { + data.Ipv4AutoAummary = types.BoolValue(value.Bool()) + } else { + data.Ipv4AutoAummary = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.bgpSupressInactive"); value.Exists() { + data.Ipv4BgpSupressInactive = types.BoolValue(value.Bool()) + } else { + data.Ipv4BgpSupressInactive = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.synchronization"); value.Exists() { + data.Ipv4Synchronization = types.BoolValue(value.Bool()) + } else { + data.Ipv4Synchronization = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.bgpRedistributeInternal"); value.Exists() { + data.Ipv4BgpRedistributeInternal = types.BoolValue(value.Bool()) + } else { + data.Ipv4BgpRedistributeInternal = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.distance.externalDistance"); value.Exists() { + data.Ipv4ExternalDistance = types.Int64Value(value.Int()) + } else { + data.Ipv4ExternalDistance = types.Int64Value(20) + } + if value := res.Get("addressFamilyIPv4.distance.internalDistance"); value.Exists() { + data.Ipv4InternalDistance = types.Int64Value(value.Int()) + } else { + data.Ipv4InternalDistance = types.Int64Value(200) + } + if value := res.Get("addressFamilyIPv4.distance.localDistance"); value.Exists() { + data.Ipv4LocalDistance = types.Int64Value(value.Int()) + } else { + data.Ipv4LocalDistance = types.Int64Value(200) + } + if value := res.Get("addressFamilyIPv4.ibgp"); value.Exists() { + data.Ipv4ForwardPacketsOverMultipathIbgp = types.Int64Value(value.Int()) + } else { + data.Ipv4ForwardPacketsOverMultipathIbgp = types.Int64Value(1) + } + if value := res.Get("addressFamilyIPv4.ebgp"); value.Exists() { + data.Ipv4ForwardPacketsOverMultipathEbgp = types.Int64Value(value.Int()) + } else { + data.Ipv4ForwardPacketsOverMultipathEbgp = types.Int64Value(1) + } + if value := res.Get("addressFamilyIPv4.neighbors"); value.Exists() { + data.Ipv4Neighbors = make([]DeviceBGPIpv4Neighbors, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4Neighbors{} + if value := res.Get("ipv4Address"); value.Exists() { + data.NeighborAddress = types.StringValue(value.String()) + } else { + data.NeighborAddress = types.StringNull() + } + if value := res.Get("remoteAs"); value.Exists() { + data.NeighborRemoteAs = types.StringValue(value.String()) + } else { + data.NeighborRemoteAs = types.StringNull() + } + if value := res.Get("neighborGeneral.fallOverBFD"); value.Exists() { + data.NeighborBfd = types.StringValue(value.String()) + } else { + data.NeighborBfd = types.StringValue("NONE") + } + if value := res.Get("neighborGeneral.updateSource.id"); value.Exists() { + data.UpdateSourceInterfaceId = types.StringValue(value.String()) + } else { + data.UpdateSourceInterfaceId = types.StringNull() + } + if value := res.Get("neighborGeneral.enableAddress"); value.Exists() { + data.EnableAddressFamily = types.BoolValue(value.Bool()) + } else { + data.EnableAddressFamily = types.BoolValue(false) + } + if value := res.Get("neighborGeneral.shutdown"); value.Exists() { + data.NeighborShutdown = types.BoolValue(value.Bool()) + } else { + data.NeighborShutdown = types.BoolValue(false) + } + if value := res.Get("neighborGeneral.description"); value.Exists() { + data.NeighborDescription = types.StringValue(value.String()) + } else { + data.NeighborDescription = types.StringNull() + } + if value := res.Get("neighborFiltering.neighborDistributeLists"); value.Exists() { + data.NeighborFilterAccessLists = make([]DeviceBGPIpv4NeighborsNeighborFilterAccessLists, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4NeighborsNeighborFilterAccessLists{} + if value := res.Get("accessList.id"); value.Exists() { + data.AccessListId = types.StringValue(value.String()) + } else { + data.AccessListId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterAccessLists = append((*parent).NeighborFilterAccessLists, data) + return true + }) + } + if value := res.Get("neighborFiltering.neighborRouteMap"); value.Exists() { + data.NeighborFilterRouteMapLists = make([]DeviceBGPIpv4NeighborsNeighborFilterRouteMapLists, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4NeighborsNeighborFilterRouteMapLists{} + if value := res.Get("RouteMap.id"); value.Exists() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterRouteMapLists = append((*parent).NeighborFilterRouteMapLists, data) + return true + }) + } + if value := res.Get("neighborFiltering.ipv4PrefixListFilter"); value.Exists() { + data.NeighborFilterPrefixLists = make([]DeviceBGPIpv4NeighborsNeighborFilterPrefixLists, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4NeighborsNeighborFilterPrefixLists{} + if value := res.Get("ipv4PrefixList.id"); value.Exists() { + data.PrefixListId = types.StringValue(value.String()) + } else { + data.PrefixListId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterPrefixLists = append((*parent).NeighborFilterPrefixLists, data) + return true + }) + } + if value := res.Get("neighborFilterList.neighborFilterList"); value.Exists() { + data.NeighborFilterAsPathLists = make([]DeviceBGPIpv4NeighborsNeighborFilterAsPathLists, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4NeighborsNeighborFilterAsPathLists{} + if value := res.Get("filterUpdateAction"); value.Exists() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + if value := res.Get("asPathList.id"); value.Exists() { + data.AsPathId = types.StringValue(value.String()) + } else { + data.AsPathId = types.StringNull() + } + (*parent).NeighborFilterAsPathLists = append((*parent).NeighborFilterAsPathLists, data) + return true + }) + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.maxPrefixLimit"); value.Exists() { + data.NeighborFilterMaxPrefix = types.Int64Value(value.Int()) + } else { + data.NeighborFilterMaxPrefix = types.Int64Null() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.warningOnly"); value.Exists() { + data.NeighborFilterWarningOnly = types.BoolValue(value.Bool()) + } else { + data.NeighborFilterWarningOnly = types.BoolNull() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.thresholdValue"); value.Exists() { + data.NeighborFilterThresholdValue = types.Int64Value(value.Int()) + } else { + data.NeighborFilterThresholdValue = types.Int64Null() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.restartInterval"); value.Exists() { + data.NeighborFilterRestartInterval = types.Int64Value(value.Int()) + } else { + data.NeighborFilterRestartInterval = types.Int64Null() + } + if value := res.Get("neighborRoutes.advertisementInterval"); value.Exists() { + data.NeighborRoutesAdvertisementInterval = types.Int64Value(value.Int()) + } else { + data.NeighborRoutesAdvertisementInterval = types.Int64Value(0) + } + if value := res.Get("neighborRoutes.removePrivateAs"); value.Exists() { + data.NeighborRoutesRemovePrivateAs = types.BoolValue(value.Bool()) + } else { + data.NeighborRoutesRemovePrivateAs = types.BoolValue(false) + } + if value := res.Get("neighborFiltering.neighborDefaultOriginate.routeMap.id"); value.Exists() { + data.NeighborGenerateDefaultRouteMapId = types.StringValue(value.String()) + } else { + data.NeighborGenerateDefaultRouteMapId = types.StringNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.existMap"); value.Exists() { + data.NeighborRoutesAdvertiseMapUseExist = types.BoolValue(value.Bool()) + } else { + data.NeighborRoutesAdvertiseMapUseExist = types.BoolNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.routeMap.id"); value.Exists() { + data.NeighborRoutesAdvertiseMapId = types.StringValue(value.String()) + } else { + data.NeighborRoutesAdvertiseMapId = types.StringNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.existRouteMap.id"); value.Exists() { + data.NeighborRoutesAdvertiseExistNonexistMapId = types.StringValue(value.String()) + } else { + data.NeighborRoutesAdvertiseExistNonexistMapId = types.StringNull() + } + if value := res.Get("neighborTimers.keepAliveInterval"); value.Exists() { + data.NeighborKeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.NeighborKeepaliveInterval = types.Int64Null() + } + if value := res.Get("neighborTimers.holdTime"); value.Exists() { + data.NeighborHoldTime = types.Int64Value(value.Int()) + } else { + data.NeighborHoldTime = types.Int64Null() + } + if value := res.Get("neighborTimers.minimumHoldTime"); value.Exists() { + data.NeighborMinHoldTime = types.Int64Value(value.Int()) + } else { + data.NeighborMinHoldTime = types.Int64Null() + } + if value := res.Get("neighborAdvanced.neighborSecret"); value.Exists() { + data.NeighborAuthenticationPassword = types.StringValue(value.String()) + } else { + data.NeighborAuthenticationPassword = types.StringNull() + } + if value := res.Get("neighborAdvanced.sendCommunity"); value.Exists() { + data.NeighborSendCommunityAttribute = types.BoolValue(value.Bool()) + } else { + data.NeighborSendCommunityAttribute = types.BoolValue(false) + } + if value := res.Get("neighborAdvanced.nextHopSelf"); value.Exists() { + data.NeighborNexthopSelf = types.BoolValue(value.Bool()) + } else { + data.NeighborNexthopSelf = types.BoolValue(false) + } + if value := res.Get("neighborAdvanced.neighborHops.disableConnectedCheck"); value.Exists() { + data.NeighborDisableConnectionVerification = types.BoolValue(value.Bool()) + } else { + data.NeighborDisableConnectionVerification = types.BoolValue(false) + } + if value := res.Get("neighborAdvanced.neighborTransportPathMTUDiscovery.disable"); value.Exists() { + data.NeighborTcpMtuPathDiscovery = types.BoolValue(value.Bool()) + } else { + data.NeighborTcpMtuPathDiscovery = types.BoolValue(false) + } + if value := res.Get("neighborAdvanced.neighborHops.maxHopCount"); value.Exists() { + data.NeighborMaxHopCount = types.Int64Value(value.Int()) + } else { + data.NeighborMaxHopCount = types.Int64Value(1) + } + if value := res.Get("neighborAdvanced.neighborTransportConnectionMode.establishTCPSession"); value.Exists() { + data.NeighborTcpTransportMode = types.BoolValue(value.Bool()) + } else { + data.NeighborTcpTransportMode = types.BoolValue(false) + } + if value := res.Get("neighborAdvanced.neighborWeight"); value.Exists() { + data.NeighborWeight = types.Int64Value(value.Int()) + } else { + data.NeighborWeight = types.Int64Value(0) + } + if value := res.Get("neighborAdvanced.neighborVersion"); value.Exists() { + data.NeighborVersion = types.StringValue(value.String()) + } else { + data.NeighborVersion = types.StringValue("0") + } + if value := res.Get("neighborLocalAs.asNumber"); value.Exists() { + data.NeighborCustomizedLocalAsNumber = types.StringValue(value.String()) + } else { + data.NeighborCustomizedLocalAsNumber = types.StringNull() + } + if value := res.Get("neighborLocalAs.noPrepend"); value.Exists() { + data.NeighborCustomizedNoPrepend = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedNoPrepend = types.BoolNull() + } + if value := res.Get("neighborLocalAs.replaceAs"); value.Exists() { + data.NeighborCustomizedReplaceAs = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedReplaceAs = types.BoolNull() + } + if value := res.Get("neighborLocalAs.dualAs"); value.Exists() { + data.NeighborCustomizedAcceptBothAs = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedAcceptBothAs = types.BoolNull() + } + (*parent).Ipv4Neighbors = append((*parent).Ipv4Neighbors, data) + return true + }) + } + if value := res.Get("addressFamilyIPv4.aggregateAddressesIPv4s"); value.Exists() { + data.Ipv4AggregateAddresses = make([]DeviceBGPIpv4AggregateAddresses, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4AggregateAddresses{} + if value := res.Get("asSet"); value.Exists() { + data.GenerateAs = types.BoolValue(value.Bool()) + } else { + data.GenerateAs = types.BoolNull() + } + if value := res.Get("summaryOnly"); value.Exists() { + data.Filter = types.BoolValue(value.Bool()) + } else { + data.Filter = types.BoolNull() + } + if value := res.Get("ipv4AggregateNetwork.id"); value.Exists() { + data.NetworkId = types.StringValue(value.String()) + } else { + data.NetworkId = types.StringNull() + } + if value := res.Get("advertiseMap.id"); value.Exists() { + data.AdvertiseMapId = types.StringValue(value.String()) + } else { + data.AdvertiseMapId = types.StringNull() + } + if value := res.Get("attributeMap.id"); value.Exists() { + data.AttributeMapId = types.StringValue(value.String()) + } else { + data.AttributeMapId = types.StringNull() + } + if value := res.Get("suppressMap.id"); value.Exists() { + data.SuppressMapId = types.StringValue(value.String()) + } else { + data.SuppressMapId = types.StringNull() + } + (*parent).Ipv4AggregateAddresses = append((*parent).Ipv4AggregateAddresses, data) + return true + }) + } + if value := res.Get("addressFamilyIPv4.distributeLists"); value.Exists() { + data.Ipv4Filterings = make([]DeviceBGPIpv4Filterings, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4Filterings{} + if value := res.Get("ipv4AggregateNetwork.id"); value.Exists() { + data.AccessListId = types.StringValue(value.String()) + } else { + data.AccessListId = types.StringNull() + } + if value := res.Get("type"); value.Exists() { + data.NetworkDirection = types.StringValue(value.String()) + } else { + data.NetworkDirection = types.StringNull() + } + if value := res.Get("protocol.protocol"); value.Exists() { + data.Protocol = types.StringValue(value.String()) + } else { + data.Protocol = types.StringNull() + } + if value := res.Get("protocol.processId"); value.Exists() { + data.ProrocolProcess = types.StringValue(value.String()) + } else { + data.ProrocolProcess = types.StringNull() + } + (*parent).Ipv4Filterings = append((*parent).Ipv4Filterings, data) + return true + }) + } + if value := res.Get("addressFamilyIPv4.networks"); value.Exists() { + data.Ipv4Networks = make([]DeviceBGPIpv4Networks, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4Networks{} + if value := res.Get("ipv4Address.id"); value.Exists() { + data.NetworkId = types.StringValue(value.String()) + } else { + data.NetworkId = types.StringNull() + } + if value := res.Get("routeMap.id"); value.Exists() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + (*parent).Ipv4Networks = append((*parent).Ipv4Networks, data) + return true + }) + } + if value := res.Get("addressFamilyIPv4.redistributeProtocols"); value.Exists() { + data.Ipv4Redistributions = make([]DeviceBGPIpv4Redistributions, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4Redistributions{} + if value := res.Get("type"); value.Exists() { + data.SourceProtocol = types.StringValue(value.String()) + } else { + data.SourceProtocol = types.StringNull() + } + if value := res.Get("routeMap.id"); value.Exists() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + if value := res.Get("routeMetric.metricValue"); value.Exists() { + data.Metric = types.Int64Value(value.Int()) + } else { + data.Metric = types.Int64Null() + } + if value := res.Get("processId"); value.Exists() { + data.ProcessId = types.StringValue(value.String()) + } else { + data.ProcessId = types.StringNull() + } + if value := res.Get("matchExternal1"); value.Exists() { + data.MatchExternal1 = types.BoolValue(value.Bool()) + } else { + data.MatchExternal1 = types.BoolNull() + } + if value := res.Get("matchExternal2"); value.Exists() { + data.MatchExternal2 = types.BoolValue(value.Bool()) + } else { + data.MatchExternal2 = types.BoolNull() + } + if value := res.Get("matchInternal"); value.Exists() { + data.MatchInternal = types.BoolValue(value.Bool()) + } else { + data.MatchInternal = types.BoolNull() + } + if value := res.Get("matchNssaExternal1"); value.Exists() { + data.MatchNssaExternal1 = types.BoolValue(value.Bool()) + } else { + data.MatchNssaExternal1 = types.BoolNull() + } + if value := res.Get("matchNssaExternal2"); value.Exists() { + data.MatchNssaExternal2 = types.BoolValue(value.Bool()) + } else { + data.MatchNssaExternal2 = types.BoolNull() + } + (*parent).Ipv4Redistributions = append((*parent).Ipv4Redistributions, data) + return true + }) + } + if value := res.Get("addressFamilyIPv4.injectMaps"); value.Exists() { + data.Ipv4RouteInjections = make([]DeviceBGPIpv4RouteInjections, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceBGPIpv4RouteInjections{} + if value := res.Get("injectMap.routeMap.id"); value.Exists() { + data.InjectRouteMapId = types.StringValue(value.String()) + } else { + data.InjectRouteMapId = types.StringNull() + } + if value := res.Get("existMap.routeMap.id"); value.Exists() { + data.ExistRouteMapId = types.StringValue(value.String()) + } else { + data.ExistRouteMapId = types.StringNull() + } + (*parent).Ipv4RouteInjections = append((*parent).Ipv4RouteInjections, data) + return true + }) + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *DeviceBGP) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("asNumber"); value.Exists() && !data.AsNumber.IsNull() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.type"); value.Exists() && !data.Ipv4AddressFamilyType.IsNull() { + data.Ipv4AddressFamilyType = types.StringValue(value.String()) + } else { + data.Ipv4AddressFamilyType = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.aftableMap.id"); value.Exists() && !data.Ipv4LearnedRouteMapId.IsNull() { + data.Ipv4LearnedRouteMapId = types.StringValue(value.String()) + } else { + data.Ipv4LearnedRouteMapId = types.StringNull() + } + if value := res.Get("addressFamilyIPv4.defaultInformationOrginate"); value.Exists() && !data.Ipv4DefaultInformationOrginate.IsNull() { + data.Ipv4DefaultInformationOrginate = types.BoolValue(value.Bool()) + } else { + data.Ipv4DefaultInformationOrginate = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.autoSummary"); value.Exists() && !data.Ipv4AutoAummary.IsNull() { + data.Ipv4AutoAummary = types.BoolValue(value.Bool()) + } else { + data.Ipv4AutoAummary = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.bgpSupressInactive"); value.Exists() && !data.Ipv4BgpSupressInactive.IsNull() { + data.Ipv4BgpSupressInactive = types.BoolValue(value.Bool()) + } else { + data.Ipv4BgpSupressInactive = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.synchronization"); value.Exists() && !data.Ipv4Synchronization.IsNull() { + data.Ipv4Synchronization = types.BoolValue(value.Bool()) + } else { + data.Ipv4Synchronization = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.bgpRedistributeInternal"); value.Exists() && !data.Ipv4BgpRedistributeInternal.IsNull() { + data.Ipv4BgpRedistributeInternal = types.BoolValue(value.Bool()) + } else { + data.Ipv4BgpRedistributeInternal = types.BoolNull() + } + if value := res.Get("addressFamilyIPv4.distance.externalDistance"); value.Exists() && !data.Ipv4ExternalDistance.IsNull() { + data.Ipv4ExternalDistance = types.Int64Value(value.Int()) + } else if data.Ipv4ExternalDistance.ValueInt64() != 20 { + data.Ipv4ExternalDistance = types.Int64Null() + } + if value := res.Get("addressFamilyIPv4.distance.internalDistance"); value.Exists() && !data.Ipv4InternalDistance.IsNull() { + data.Ipv4InternalDistance = types.Int64Value(value.Int()) + } else if data.Ipv4InternalDistance.ValueInt64() != 200 { + data.Ipv4InternalDistance = types.Int64Null() + } + if value := res.Get("addressFamilyIPv4.distance.localDistance"); value.Exists() && !data.Ipv4LocalDistance.IsNull() { + data.Ipv4LocalDistance = types.Int64Value(value.Int()) + } else if data.Ipv4LocalDistance.ValueInt64() != 200 { + data.Ipv4LocalDistance = types.Int64Null() + } + if value := res.Get("addressFamilyIPv4.ibgp"); value.Exists() && !data.Ipv4ForwardPacketsOverMultipathIbgp.IsNull() { + data.Ipv4ForwardPacketsOverMultipathIbgp = types.Int64Value(value.Int()) + } else if data.Ipv4ForwardPacketsOverMultipathIbgp.ValueInt64() != 1 { + data.Ipv4ForwardPacketsOverMultipathIbgp = types.Int64Null() + } + if value := res.Get("addressFamilyIPv4.ebgp"); value.Exists() && !data.Ipv4ForwardPacketsOverMultipathEbgp.IsNull() { + data.Ipv4ForwardPacketsOverMultipathEbgp = types.Int64Value(value.Int()) + } else if data.Ipv4ForwardPacketsOverMultipathEbgp.ValueInt64() != 1 { + data.Ipv4ForwardPacketsOverMultipathEbgp = types.Int64Null() + } + for i := 0; i < len(data.Ipv4Neighbors); i++ { + keys := [...]string{"ipv4Address", "remoteAs", "neighborRoutes.neighborAdvertiseMaps.routeMap.id", "neighborRoutes.neighborAdvertiseMaps.existRouteMap.id"} + keyValues := [...]string{data.Ipv4Neighbors[i].NeighborAddress.ValueString(), data.Ipv4Neighbors[i].NeighborRemoteAs.ValueString(), data.Ipv4Neighbors[i].NeighborRoutesAdvertiseMapId.ValueString(), data.Ipv4Neighbors[i].NeighborRoutesAdvertiseExistNonexistMapId.ValueString()} + + parent := &data + data := (*parent).Ipv4Neighbors[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.neighbors").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4Neighbors[%d] = %+v", + i, + (*parent).Ipv4Neighbors[i], + )) + (*parent).Ipv4Neighbors = slices.Delete((*parent).Ipv4Neighbors, i, i+1) + i-- + + continue + } + if value := res.Get("ipv4Address"); value.Exists() && !data.NeighborAddress.IsNull() { + data.NeighborAddress = types.StringValue(value.String()) + } else { + data.NeighborAddress = types.StringNull() + } + if value := res.Get("remoteAs"); value.Exists() && !data.NeighborRemoteAs.IsNull() { + data.NeighborRemoteAs = types.StringValue(value.String()) + } else { + data.NeighborRemoteAs = types.StringNull() + } + if value := res.Get("neighborGeneral.fallOverBFD"); value.Exists() && !data.NeighborBfd.IsNull() { + data.NeighborBfd = types.StringValue(value.String()) + } else if data.NeighborBfd.ValueString() != "NONE" { + data.NeighborBfd = types.StringNull() + } + if value := res.Get("neighborGeneral.updateSource.id"); value.Exists() && !data.UpdateSourceInterfaceId.IsNull() { + data.UpdateSourceInterfaceId = types.StringValue(value.String()) + } else { + data.UpdateSourceInterfaceId = types.StringNull() + } + if value := res.Get("neighborGeneral.enableAddress"); value.Exists() && !data.EnableAddressFamily.IsNull() { + data.EnableAddressFamily = types.BoolValue(value.Bool()) + } else if data.EnableAddressFamily.ValueBool() != false { + data.EnableAddressFamily = types.BoolNull() + } + if value := res.Get("neighborGeneral.shutdown"); value.Exists() && !data.NeighborShutdown.IsNull() { + data.NeighborShutdown = types.BoolValue(value.Bool()) + } else if data.NeighborShutdown.ValueBool() != false { + data.NeighborShutdown = types.BoolNull() + } + if value := res.Get("neighborGeneral.description"); value.Exists() && !data.NeighborDescription.IsNull() { + data.NeighborDescription = types.StringValue(value.String()) + } else { + data.NeighborDescription = types.StringNull() + } + for i := 0; i < len(data.NeighborFilterAccessLists); i++ { + keys := [...]string{"accessList.id", "filterUpdateAction"} + keyValues := [...]string{data.NeighborFilterAccessLists[i].AccessListId.ValueString(), data.NeighborFilterAccessLists[i].UpdateDirection.ValueString()} + + parent := &data + data := (*parent).NeighborFilterAccessLists[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("neighborFiltering.neighborDistributeLists").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing NeighborFilterAccessLists[%d] = %+v", + i, + (*parent).NeighborFilterAccessLists[i], + )) + (*parent).NeighborFilterAccessLists = slices.Delete((*parent).NeighborFilterAccessLists, i, i+1) + i-- + + continue + } + if value := res.Get("accessList.id"); value.Exists() && !data.AccessListId.IsNull() { + data.AccessListId = types.StringValue(value.String()) + } else { + data.AccessListId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() && !data.UpdateDirection.IsNull() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterAccessLists[i] = data + } + for i := 0; i < len(data.NeighborFilterRouteMapLists); i++ { + keys := [...]string{"RouteMap.id", "filterUpdateAction"} + keyValues := [...]string{data.NeighborFilterRouteMapLists[i].RouteMapId.ValueString(), data.NeighborFilterRouteMapLists[i].UpdateDirection.ValueString()} + + parent := &data + data := (*parent).NeighborFilterRouteMapLists[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("neighborFiltering.neighborRouteMap").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing NeighborFilterRouteMapLists[%d] = %+v", + i, + (*parent).NeighborFilterRouteMapLists[i], + )) + (*parent).NeighborFilterRouteMapLists = slices.Delete((*parent).NeighborFilterRouteMapLists, i, i+1) + i-- + + continue + } + if value := res.Get("RouteMap.id"); value.Exists() && !data.RouteMapId.IsNull() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() && !data.UpdateDirection.IsNull() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterRouteMapLists[i] = data + } + for i := 0; i < len(data.NeighborFilterPrefixLists); i++ { + keys := [...]string{"ipv4PrefixList.id", "filterUpdateAction"} + keyValues := [...]string{data.NeighborFilterPrefixLists[i].PrefixListId.ValueString(), data.NeighborFilterPrefixLists[i].UpdateDirection.ValueString()} + + parent := &data + data := (*parent).NeighborFilterPrefixLists[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("neighborFiltering.ipv4PrefixListFilter").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing NeighborFilterPrefixLists[%d] = %+v", + i, + (*parent).NeighborFilterPrefixLists[i], + )) + (*parent).NeighborFilterPrefixLists = slices.Delete((*parent).NeighborFilterPrefixLists, i, i+1) + i-- + + continue + } + if value := res.Get("ipv4PrefixList.id"); value.Exists() && !data.PrefixListId.IsNull() { + data.PrefixListId = types.StringValue(value.String()) + } else { + data.PrefixListId = types.StringNull() + } + if value := res.Get("filterUpdateAction"); value.Exists() && !data.UpdateDirection.IsNull() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + (*parent).NeighborFilterPrefixLists[i] = data + } + for i := 0; i < len(data.NeighborFilterAsPathLists); i++ { + keys := [...]string{"filterUpdateAction", "asPathList.id"} + keyValues := [...]string{data.NeighborFilterAsPathLists[i].UpdateDirection.ValueString(), data.NeighborFilterAsPathLists[i].AsPathId.ValueString()} + + parent := &data + data := (*parent).NeighborFilterAsPathLists[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("neighborFilterList.neighborFilterList").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing NeighborFilterAsPathLists[%d] = %+v", + i, + (*parent).NeighborFilterAsPathLists[i], + )) + (*parent).NeighborFilterAsPathLists = slices.Delete((*parent).NeighborFilterAsPathLists, i, i+1) + i-- + + continue + } + if value := res.Get("filterUpdateAction"); value.Exists() && !data.UpdateDirection.IsNull() { + data.UpdateDirection = types.StringValue(value.String()) + } else { + data.UpdateDirection = types.StringNull() + } + if value := res.Get("asPathList.id"); value.Exists() && !data.AsPathId.IsNull() { + data.AsPathId = types.StringValue(value.String()) + } else { + data.AsPathId = types.StringNull() + } + (*parent).NeighborFilterAsPathLists[i] = data + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.maxPrefixLimit"); value.Exists() && !data.NeighborFilterMaxPrefix.IsNull() { + data.NeighborFilterMaxPrefix = types.Int64Value(value.Int()) + } else { + data.NeighborFilterMaxPrefix = types.Int64Null() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.warningOnly"); value.Exists() && !data.NeighborFilterWarningOnly.IsNull() { + data.NeighborFilterWarningOnly = types.BoolValue(value.Bool()) + } else { + data.NeighborFilterWarningOnly = types.BoolNull() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.thresholdValue"); value.Exists() && !data.NeighborFilterThresholdValue.IsNull() { + data.NeighborFilterThresholdValue = types.Int64Value(value.Int()) + } else { + data.NeighborFilterThresholdValue = types.Int64Null() + } + if value := res.Get("neighborFiltering.neighborMaximumPrefix.restartInterval"); value.Exists() && !data.NeighborFilterRestartInterval.IsNull() { + data.NeighborFilterRestartInterval = types.Int64Value(value.Int()) + } else { + data.NeighborFilterRestartInterval = types.Int64Null() + } + if value := res.Get("neighborRoutes.advertisementInterval"); value.Exists() && !data.NeighborRoutesAdvertisementInterval.IsNull() { + data.NeighborRoutesAdvertisementInterval = types.Int64Value(value.Int()) + } else if data.NeighborRoutesAdvertisementInterval.ValueInt64() != 0 { + data.NeighborRoutesAdvertisementInterval = types.Int64Null() + } + if value := res.Get("neighborRoutes.removePrivateAs"); value.Exists() && !data.NeighborRoutesRemovePrivateAs.IsNull() { + data.NeighborRoutesRemovePrivateAs = types.BoolValue(value.Bool()) + } else if data.NeighborRoutesRemovePrivateAs.ValueBool() != false { + data.NeighborRoutesRemovePrivateAs = types.BoolNull() + } + if value := res.Get("neighborFiltering.neighborDefaultOriginate.routeMap.id"); value.Exists() && !data.NeighborGenerateDefaultRouteMapId.IsNull() { + data.NeighborGenerateDefaultRouteMapId = types.StringValue(value.String()) + } else { + data.NeighborGenerateDefaultRouteMapId = types.StringNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.existMap"); value.Exists() && !data.NeighborRoutesAdvertiseMapUseExist.IsNull() { + data.NeighborRoutesAdvertiseMapUseExist = types.BoolValue(value.Bool()) + } else { + data.NeighborRoutesAdvertiseMapUseExist = types.BoolNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.routeMap.id"); value.Exists() && !data.NeighborRoutesAdvertiseMapId.IsNull() { + data.NeighborRoutesAdvertiseMapId = types.StringValue(value.String()) + } else { + data.NeighborRoutesAdvertiseMapId = types.StringNull() + } + if value := res.Get("neighborRoutes.neighborAdvertiseMaps.existRouteMap.id"); value.Exists() && !data.NeighborRoutesAdvertiseExistNonexistMapId.IsNull() { + data.NeighborRoutesAdvertiseExistNonexistMapId = types.StringValue(value.String()) + } else { + data.NeighborRoutesAdvertiseExistNonexistMapId = types.StringNull() + } + if value := res.Get("neighborTimers.keepAliveInterval"); value.Exists() && !data.NeighborKeepaliveInterval.IsNull() { + data.NeighborKeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.NeighborKeepaliveInterval = types.Int64Null() + } + if value := res.Get("neighborTimers.holdTime"); value.Exists() && !data.NeighborHoldTime.IsNull() { + data.NeighborHoldTime = types.Int64Value(value.Int()) + } else { + data.NeighborHoldTime = types.Int64Null() + } + if value := res.Get("neighborTimers.minimumHoldTime"); value.Exists() && !data.NeighborMinHoldTime.IsNull() { + data.NeighborMinHoldTime = types.Int64Value(value.Int()) + } else { + data.NeighborMinHoldTime = types.Int64Null() + } + if value := res.Get("neighborAdvanced.neighborSecret"); value.Exists() && !data.NeighborAuthenticationPassword.IsNull() { + data.NeighborAuthenticationPassword = types.StringValue(value.String()) + } else { + data.NeighborAuthenticationPassword = types.StringNull() + } + if value := res.Get("neighborAdvanced.sendCommunity"); value.Exists() && !data.NeighborSendCommunityAttribute.IsNull() { + data.NeighborSendCommunityAttribute = types.BoolValue(value.Bool()) + } else if data.NeighborSendCommunityAttribute.ValueBool() != false { + data.NeighborSendCommunityAttribute = types.BoolNull() + } + if value := res.Get("neighborAdvanced.nextHopSelf"); value.Exists() && !data.NeighborNexthopSelf.IsNull() { + data.NeighborNexthopSelf = types.BoolValue(value.Bool()) + } else if data.NeighborNexthopSelf.ValueBool() != false { + data.NeighborNexthopSelf = types.BoolNull() + } + if value := res.Get("neighborAdvanced.neighborHops.disableConnectedCheck"); value.Exists() && !data.NeighborDisableConnectionVerification.IsNull() { + data.NeighborDisableConnectionVerification = types.BoolValue(value.Bool()) + } else if data.NeighborDisableConnectionVerification.ValueBool() != false { + data.NeighborDisableConnectionVerification = types.BoolNull() + } + if value := res.Get("neighborAdvanced.neighborTransportPathMTUDiscovery.disable"); value.Exists() && !data.NeighborTcpMtuPathDiscovery.IsNull() { + data.NeighborTcpMtuPathDiscovery = types.BoolValue(value.Bool()) + } else if data.NeighborTcpMtuPathDiscovery.ValueBool() != false { + data.NeighborTcpMtuPathDiscovery = types.BoolNull() + } + if value := res.Get("neighborAdvanced.neighborHops.maxHopCount"); value.Exists() && !data.NeighborMaxHopCount.IsNull() { + data.NeighborMaxHopCount = types.Int64Value(value.Int()) + } else if data.NeighborMaxHopCount.ValueInt64() != 1 { + data.NeighborMaxHopCount = types.Int64Null() + } + if value := res.Get("neighborAdvanced.neighborTransportConnectionMode.establishTCPSession"); value.Exists() && !data.NeighborTcpTransportMode.IsNull() { + data.NeighborTcpTransportMode = types.BoolValue(value.Bool()) + } else if data.NeighborTcpTransportMode.ValueBool() != false { + data.NeighborTcpTransportMode = types.BoolNull() + } + if value := res.Get("neighborAdvanced.neighborWeight"); value.Exists() && !data.NeighborWeight.IsNull() { + data.NeighborWeight = types.Int64Value(value.Int()) + } else if data.NeighborWeight.ValueInt64() != 0 { + data.NeighborWeight = types.Int64Null() + } + if value := res.Get("neighborAdvanced.neighborVersion"); value.Exists() && !data.NeighborVersion.IsNull() { + data.NeighborVersion = types.StringValue(value.String()) + } else if data.NeighborVersion.ValueString() != "0" { + data.NeighborVersion = types.StringNull() + } + if value := res.Get("neighborLocalAs.asNumber"); value.Exists() && !data.NeighborCustomizedLocalAsNumber.IsNull() { + data.NeighborCustomizedLocalAsNumber = types.StringValue(value.String()) + } else { + data.NeighborCustomizedLocalAsNumber = types.StringNull() + } + if value := res.Get("neighborLocalAs.noPrepend"); value.Exists() && !data.NeighborCustomizedNoPrepend.IsNull() { + data.NeighborCustomizedNoPrepend = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedNoPrepend = types.BoolNull() + } + if value := res.Get("neighborLocalAs.replaceAs"); value.Exists() && !data.NeighborCustomizedReplaceAs.IsNull() { + data.NeighborCustomizedReplaceAs = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedReplaceAs = types.BoolNull() + } + if value := res.Get("neighborLocalAs.dualAs"); value.Exists() && !data.NeighborCustomizedAcceptBothAs.IsNull() { + data.NeighborCustomizedAcceptBothAs = types.BoolValue(value.Bool()) + } else { + data.NeighborCustomizedAcceptBothAs = types.BoolNull() + } + (*parent).Ipv4Neighbors[i] = data + } + for i := 0; i < len(data.Ipv4AggregateAddresses); i++ { + keys := [...]string{"ipv4AggregateNetwork.id", "advertiseMap.id", "attributeMap.id", "suppressMap.id"} + keyValues := [...]string{data.Ipv4AggregateAddresses[i].NetworkId.ValueString(), data.Ipv4AggregateAddresses[i].AdvertiseMapId.ValueString(), data.Ipv4AggregateAddresses[i].AttributeMapId.ValueString(), data.Ipv4AggregateAddresses[i].SuppressMapId.ValueString()} + + parent := &data + data := (*parent).Ipv4AggregateAddresses[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.aggregateAddressesIPv4s").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4AggregateAddresses[%d] = %+v", + i, + (*parent).Ipv4AggregateAddresses[i], + )) + (*parent).Ipv4AggregateAddresses = slices.Delete((*parent).Ipv4AggregateAddresses, i, i+1) + i-- + + continue + } + if value := res.Get("asSet"); value.Exists() && !data.GenerateAs.IsNull() { + data.GenerateAs = types.BoolValue(value.Bool()) + } else { + data.GenerateAs = types.BoolNull() + } + if value := res.Get("summaryOnly"); value.Exists() && !data.Filter.IsNull() { + data.Filter = types.BoolValue(value.Bool()) + } else { + data.Filter = types.BoolNull() + } + if value := res.Get("ipv4AggregateNetwork.id"); value.Exists() && !data.NetworkId.IsNull() { + data.NetworkId = types.StringValue(value.String()) + } else { + data.NetworkId = types.StringNull() + } + if value := res.Get("advertiseMap.id"); value.Exists() && !data.AdvertiseMapId.IsNull() { + data.AdvertiseMapId = types.StringValue(value.String()) + } else { + data.AdvertiseMapId = types.StringNull() + } + if value := res.Get("attributeMap.id"); value.Exists() && !data.AttributeMapId.IsNull() { + data.AttributeMapId = types.StringValue(value.String()) + } else { + data.AttributeMapId = types.StringNull() + } + if value := res.Get("suppressMap.id"); value.Exists() && !data.SuppressMapId.IsNull() { + data.SuppressMapId = types.StringValue(value.String()) + } else { + data.SuppressMapId = types.StringNull() + } + (*parent).Ipv4AggregateAddresses[i] = data + } + for i := 0; i < len(data.Ipv4Filterings); i++ { + keys := [...]string{"ipv4AggregateNetwork.id"} + keyValues := [...]string{data.Ipv4Filterings[i].AccessListId.ValueString()} + + parent := &data + data := (*parent).Ipv4Filterings[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.distributeLists").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4Filterings[%d] = %+v", + i, + (*parent).Ipv4Filterings[i], + )) + (*parent).Ipv4Filterings = slices.Delete((*parent).Ipv4Filterings, i, i+1) + i-- + + continue + } + if value := res.Get("ipv4AggregateNetwork.id"); value.Exists() && !data.AccessListId.IsNull() { + data.AccessListId = types.StringValue(value.String()) + } else { + data.AccessListId = types.StringNull() + } + if value := res.Get("type"); value.Exists() && !data.NetworkDirection.IsNull() { + data.NetworkDirection = types.StringValue(value.String()) + } else { + data.NetworkDirection = types.StringNull() + } + if value := res.Get("protocol.protocol"); value.Exists() && !data.Protocol.IsNull() { + data.Protocol = types.StringValue(value.String()) + } else { + data.Protocol = types.StringNull() + } + if value := res.Get("protocol.processId"); value.Exists() && !data.ProrocolProcess.IsNull() { + data.ProrocolProcess = types.StringValue(value.String()) + } else { + data.ProrocolProcess = types.StringNull() + } + (*parent).Ipv4Filterings[i] = data + } + for i := 0; i < len(data.Ipv4Networks); i++ { + keys := [...]string{"ipv4Address.id", "routeMap.id"} + keyValues := [...]string{data.Ipv4Networks[i].NetworkId.ValueString(), data.Ipv4Networks[i].RouteMapId.ValueString()} + + parent := &data + data := (*parent).Ipv4Networks[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.networks").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4Networks[%d] = %+v", + i, + (*parent).Ipv4Networks[i], + )) + (*parent).Ipv4Networks = slices.Delete((*parent).Ipv4Networks, i, i+1) + i-- + + continue + } + if value := res.Get("ipv4Address.id"); value.Exists() && !data.NetworkId.IsNull() { + data.NetworkId = types.StringValue(value.String()) + } else { + data.NetworkId = types.StringNull() + } + if value := res.Get("routeMap.id"); value.Exists() && !data.RouteMapId.IsNull() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + (*parent).Ipv4Networks[i] = data + } + for i := 0; i < len(data.Ipv4Redistributions); i++ { + keys := [...]string{"routeMap.id"} + keyValues := [...]string{data.Ipv4Redistributions[i].RouteMapId.ValueString()} + + parent := &data + data := (*parent).Ipv4Redistributions[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.redistributeProtocols").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4Redistributions[%d] = %+v", + i, + (*parent).Ipv4Redistributions[i], + )) + (*parent).Ipv4Redistributions = slices.Delete((*parent).Ipv4Redistributions, i, i+1) + i-- + + continue + } + if value := res.Get("type"); value.Exists() && !data.SourceProtocol.IsNull() { + data.SourceProtocol = types.StringValue(value.String()) + } else { + data.SourceProtocol = types.StringNull() + } + if value := res.Get("routeMap.id"); value.Exists() && !data.RouteMapId.IsNull() { + data.RouteMapId = types.StringValue(value.String()) + } else { + data.RouteMapId = types.StringNull() + } + if value := res.Get("routeMetric.metricValue"); value.Exists() && !data.Metric.IsNull() { + data.Metric = types.Int64Value(value.Int()) + } else { + data.Metric = types.Int64Null() + } + if value := res.Get("processId"); value.Exists() && !data.ProcessId.IsNull() { + data.ProcessId = types.StringValue(value.String()) + } else { + data.ProcessId = types.StringNull() + } + if value := res.Get("matchExternal1"); value.Exists() && !data.MatchExternal1.IsNull() { + data.MatchExternal1 = types.BoolValue(value.Bool()) + } else { + data.MatchExternal1 = types.BoolNull() + } + if value := res.Get("matchExternal2"); value.Exists() && !data.MatchExternal2.IsNull() { + data.MatchExternal2 = types.BoolValue(value.Bool()) + } else { + data.MatchExternal2 = types.BoolNull() + } + if value := res.Get("matchInternal"); value.Exists() && !data.MatchInternal.IsNull() { + data.MatchInternal = types.BoolValue(value.Bool()) + } else { + data.MatchInternal = types.BoolNull() + } + if value := res.Get("matchNssaExternal1"); value.Exists() && !data.MatchNssaExternal1.IsNull() { + data.MatchNssaExternal1 = types.BoolValue(value.Bool()) + } else { + data.MatchNssaExternal1 = types.BoolNull() + } + if value := res.Get("matchNssaExternal2"); value.Exists() && !data.MatchNssaExternal2.IsNull() { + data.MatchNssaExternal2 = types.BoolValue(value.Bool()) + } else { + data.MatchNssaExternal2 = types.BoolNull() + } + (*parent).Ipv4Redistributions[i] = data + } + for i := 0; i < len(data.Ipv4RouteInjections); i++ { + keys := [...]string{"injectMap.routeMap.id", "existMap.routeMap.id"} + keyValues := [...]string{data.Ipv4RouteInjections[i].InjectRouteMapId.ValueString(), data.Ipv4RouteInjections[i].ExistRouteMapId.ValueString()} + + parent := &data + data := (*parent).Ipv4RouteInjections[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("addressFamilyIPv4.injectMaps").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv4RouteInjections[%d] = %+v", + i, + (*parent).Ipv4RouteInjections[i], + )) + (*parent).Ipv4RouteInjections = slices.Delete((*parent).Ipv4RouteInjections, i, i+1) + i-- + + continue + } + if value := res.Get("injectMap.routeMap.id"); value.Exists() && !data.InjectRouteMapId.IsNull() { + data.InjectRouteMapId = types.StringValue(value.String()) + } else { + data.InjectRouteMapId = types.StringNull() + } + if value := res.Get("existMap.routeMap.id"); value.Exists() && !data.ExistRouteMapId.IsNull() { + data.ExistRouteMapId = types.StringValue(value.String()) + } else { + data.ExistRouteMapId = types.StringNull() + } + (*parent).Ipv4RouteInjections[i] = data + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *DeviceBGP) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Name.IsUnknown() { + if value := res.Get("name"); value.Exists() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + } + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } + if data.AsNumber.IsUnknown() { + if value := res.Get("asNumber"); value.Exists() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + } + if data.Ipv4AddressFamilyType.IsUnknown() { + if value := res.Get("addressFamilyIPv4.type"); value.Exists() { + data.Ipv4AddressFamilyType = types.StringValue(value.String()) + } else { + data.Ipv4AddressFamilyType = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_device_bgp_general_settings.go b/internal/provider/model_fmc_device_bgp_general_settings.go new file mode 100644 index 00000000..ce960e0b --- /dev/null +++ b/internal/provider/model_fmc_device_bgp_general_settings.go @@ -0,0 +1,436 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type DeviceBGPGeneralSettings struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + DeviceId types.String `tfsdk:"device_id"` + Name types.String `tfsdk:"name"` + AsNumber types.String `tfsdk:"as_number"` + RouterId types.String `tfsdk:"router_id"` + ScanningInterval types.Int64 `tfsdk:"scanning_interval"` + AsNumberInPathAttribute types.Int64 `tfsdk:"as_number_in_path_attribute"` + LogNeighborChanges types.Bool `tfsdk:"log_neighbor_changes"` + TcpPathMtuDiscovery types.Bool `tfsdk:"tcp_path_mtu_discovery"` + ResetSessionUponFailover types.Bool `tfsdk:"reset_session_upon_failover"` + EnforceFirstPeerAs types.Bool `tfsdk:"enforce_first_peer_as"` + UseDotNotation types.Bool `tfsdk:"use_dot_notation"` + AggregateTimer types.Int64 `tfsdk:"aggregate_timer"` + DefaultLocalPreference types.Int64 `tfsdk:"default_local_preference"` + CompareMedFromDifferentNeighbors types.Bool `tfsdk:"compare_med_from_different_neighbors"` + CompareRouterIdInPath types.Bool `tfsdk:"compare_router_id_in_path"` + PickBestMed types.Bool `tfsdk:"pick_best_med"` + MissingMedAsBest types.Bool `tfsdk:"missing_med_as_best"` + KeepaliveInterval types.Int64 `tfsdk:"keepalive_interval"` + HoldTime types.Int64 `tfsdk:"hold_time"` + MinHoldTime types.Int64 `tfsdk:"min_hold_time"` + NextHopAddressTracking types.Bool `tfsdk:"next_hop_address_tracking"` + NextHopDelayInterval types.Int64 `tfsdk:"next_hop_delay_interval"` + GracefulRestart types.Bool `tfsdk:"graceful_restart"` + GracefulRestartRestartTime types.Int64 `tfsdk:"graceful_restart_restart_time"` + GracefulRestartStalePathTime types.Int64 `tfsdk:"graceful_restart_stale_path_time"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceBGPGeneralSettings) getPath() string { + return fmt.Sprintf("/api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bgpgeneralsettings", url.QueryEscape(data.DeviceId.ValueString())) +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceBGPGeneralSettings) toBody(ctx context.Context, state DeviceBGPGeneralSettings) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.AsNumber.IsNull() { + body, _ = sjson.Set(body, "asNumber", data.AsNumber.ValueString()) + } + if !data.RouterId.IsNull() { + body, _ = sjson.Set(body, "routerId", data.RouterId.ValueString()) + } + if !data.ScanningInterval.IsNull() { + body, _ = sjson.Set(body, "scanTime", data.ScanningInterval.ValueInt64()) + } + if !data.AsNumberInPathAttribute.IsNull() { + body, _ = sjson.Set(body, "maxasLimit", data.AsNumberInPathAttribute.ValueInt64()) + } + if !data.LogNeighborChanges.IsNull() { + body, _ = sjson.Set(body, "logNeighborChanges", data.LogNeighborChanges.ValueBool()) + } + if !data.TcpPathMtuDiscovery.IsNull() { + body, _ = sjson.Set(body, "transportPathMtuDiscovery", data.TcpPathMtuDiscovery.ValueBool()) + } + if !data.ResetSessionUponFailover.IsNull() { + body, _ = sjson.Set(body, "fastExternalFallOver", data.ResetSessionUponFailover.ValueBool()) + } + if !data.EnforceFirstPeerAs.IsNull() { + body, _ = sjson.Set(body, "enforceFirstAs", data.EnforceFirstPeerAs.ValueBool()) + } + if !data.UseDotNotation.IsNull() { + body, _ = sjson.Set(body, "asnotationDot", data.UseDotNotation.ValueBool()) + } + if !data.AggregateTimer.IsNull() { + body, _ = sjson.Set(body, "aggregateTimer", data.AggregateTimer.ValueInt64()) + } + if !data.DefaultLocalPreference.IsNull() { + body, _ = sjson.Set(body, "bestPath.defaultLocalPreferenceValue", data.DefaultLocalPreference.ValueInt64()) + } + if !data.CompareMedFromDifferentNeighbors.IsNull() { + body, _ = sjson.Set(body, "bestPath.alwaysCompareMed", data.CompareMedFromDifferentNeighbors.ValueBool()) + } + if !data.CompareRouterIdInPath.IsNull() { + body, _ = sjson.Set(body, "bestPath.deterministicMed", data.CompareRouterIdInPath.ValueBool()) + } + if !data.PickBestMed.IsNull() { + body, _ = sjson.Set(body, "bestPath.bestPathCompareRouterId", data.PickBestMed.ValueBool()) + } + if !data.MissingMedAsBest.IsNull() { + body, _ = sjson.Set(body, "bestPath.bestPathMedMissingAsWorst", data.MissingMedAsBest.ValueBool()) + } + if !data.KeepaliveInterval.IsNull() { + body, _ = sjson.Set(body, "bgptimers.keepAlive", data.KeepaliveInterval.ValueInt64()) + } + if !data.HoldTime.IsNull() { + body, _ = sjson.Set(body, "bgptimers.holdTime", data.HoldTime.ValueInt64()) + } + if !data.MinHoldTime.IsNull() { + body, _ = sjson.Set(body, "bgptimers.minHoldTime", data.MinHoldTime.ValueInt64()) + } + if !data.NextHopAddressTracking.IsNull() { + body, _ = sjson.Set(body, "bgpNextHopTriggerEnable", data.NextHopAddressTracking.ValueBool()) + } + if !data.NextHopDelayInterval.IsNull() { + body, _ = sjson.Set(body, "bgpNextHopTriggerDelay", data.NextHopDelayInterval.ValueInt64()) + } + if !data.GracefulRestart.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestart", data.GracefulRestart.ValueBool()) + } + if !data.GracefulRestartRestartTime.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestartRestartTime", data.GracefulRestartRestartTime.ValueInt64()) + } + if !data.GracefulRestartStalePathTime.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestartStalePathTime", data.GracefulRestartStalePathTime.ValueInt64()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceBGPGeneralSettings) 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("asNumber"); value.Exists() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("routerId"); value.Exists() { + data.RouterId = types.StringValue(value.String()) + } else { + data.RouterId = types.StringNull() + } + if value := res.Get("scanTime"); value.Exists() { + data.ScanningInterval = types.Int64Value(value.Int()) + } else { + data.ScanningInterval = types.Int64Null() + } + if value := res.Get("maxasLimit"); value.Exists() { + data.AsNumberInPathAttribute = types.Int64Value(value.Int()) + } else { + data.AsNumberInPathAttribute = types.Int64Null() + } + if value := res.Get("logNeighborChanges"); value.Exists() { + data.LogNeighborChanges = types.BoolValue(value.Bool()) + } else { + data.LogNeighborChanges = types.BoolNull() + } + if value := res.Get("transportPathMtuDiscovery"); value.Exists() { + data.TcpPathMtuDiscovery = types.BoolValue(value.Bool()) + } else { + data.TcpPathMtuDiscovery = types.BoolNull() + } + if value := res.Get("fastExternalFallOver"); value.Exists() { + data.ResetSessionUponFailover = types.BoolValue(value.Bool()) + } else { + data.ResetSessionUponFailover = types.BoolNull() + } + if value := res.Get("enforceFirstAs"); value.Exists() { + data.EnforceFirstPeerAs = types.BoolValue(value.Bool()) + } else { + data.EnforceFirstPeerAs = types.BoolNull() + } + if value := res.Get("asnotationDot"); value.Exists() { + data.UseDotNotation = types.BoolValue(value.Bool()) + } else { + data.UseDotNotation = types.BoolNull() + } + if value := res.Get("aggregateTimer"); value.Exists() { + data.AggregateTimer = types.Int64Value(value.Int()) + } else { + data.AggregateTimer = types.Int64Null() + } + if value := res.Get("bestPath.defaultLocalPreferenceValue"); value.Exists() { + data.DefaultLocalPreference = types.Int64Value(value.Int()) + } else { + data.DefaultLocalPreference = types.Int64Null() + } + if value := res.Get("bestPath.alwaysCompareMed"); value.Exists() { + data.CompareMedFromDifferentNeighbors = types.BoolValue(value.Bool()) + } else { + data.CompareMedFromDifferentNeighbors = types.BoolNull() + } + if value := res.Get("bestPath.deterministicMed"); value.Exists() { + data.CompareRouterIdInPath = types.BoolValue(value.Bool()) + } else { + data.CompareRouterIdInPath = types.BoolNull() + } + if value := res.Get("bestPath.bestPathCompareRouterId"); value.Exists() { + data.PickBestMed = types.BoolValue(value.Bool()) + } else { + data.PickBestMed = types.BoolNull() + } + if value := res.Get("bestPath.bestPathMedMissingAsWorst"); value.Exists() { + data.MissingMedAsBest = types.BoolValue(value.Bool()) + } else { + data.MissingMedAsBest = types.BoolNull() + } + if value := res.Get("bgptimers.keepAlive"); value.Exists() { + data.KeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.KeepaliveInterval = types.Int64Null() + } + if value := res.Get("bgptimers.holdTime"); value.Exists() { + data.HoldTime = types.Int64Value(value.Int()) + } else { + data.HoldTime = types.Int64Null() + } + if value := res.Get("bgptimers.minHoldTime"); value.Exists() { + data.MinHoldTime = types.Int64Value(value.Int()) + } else { + data.MinHoldTime = types.Int64Null() + } + if value := res.Get("bgpNextHopTriggerEnable"); value.Exists() { + data.NextHopAddressTracking = types.BoolValue(value.Bool()) + } else { + data.NextHopAddressTracking = types.BoolNull() + } + if value := res.Get("bgpNextHopTriggerDelay"); value.Exists() { + data.NextHopDelayInterval = types.Int64Value(value.Int()) + } else { + data.NextHopDelayInterval = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestart"); value.Exists() { + data.GracefulRestart = types.BoolValue(value.Bool()) + } else { + data.GracefulRestart = types.BoolNull() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartRestartTime"); value.Exists() { + data.GracefulRestartRestartTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartRestartTime = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartStalePathTime"); value.Exists() { + data.GracefulRestartStalePathTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartStalePathTime = types.Int64Null() + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *DeviceBGPGeneralSettings) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + if value := res.Get("asNumber"); value.Exists() && !data.AsNumber.IsNull() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("routerId"); value.Exists() && !data.RouterId.IsNull() { + data.RouterId = types.StringValue(value.String()) + } else { + data.RouterId = types.StringNull() + } + if value := res.Get("scanTime"); value.Exists() && !data.ScanningInterval.IsNull() { + data.ScanningInterval = types.Int64Value(value.Int()) + } else { + data.ScanningInterval = types.Int64Null() + } + if value := res.Get("maxasLimit"); value.Exists() && !data.AsNumberInPathAttribute.IsNull() { + data.AsNumberInPathAttribute = types.Int64Value(value.Int()) + } else { + data.AsNumberInPathAttribute = types.Int64Null() + } + if value := res.Get("logNeighborChanges"); value.Exists() && !data.LogNeighborChanges.IsNull() { + data.LogNeighborChanges = types.BoolValue(value.Bool()) + } else { + data.LogNeighborChanges = types.BoolNull() + } + if value := res.Get("transportPathMtuDiscovery"); value.Exists() && !data.TcpPathMtuDiscovery.IsNull() { + data.TcpPathMtuDiscovery = types.BoolValue(value.Bool()) + } else { + data.TcpPathMtuDiscovery = types.BoolNull() + } + if value := res.Get("fastExternalFallOver"); value.Exists() && !data.ResetSessionUponFailover.IsNull() { + data.ResetSessionUponFailover = types.BoolValue(value.Bool()) + } else { + data.ResetSessionUponFailover = types.BoolNull() + } + if value := res.Get("enforceFirstAs"); value.Exists() && !data.EnforceFirstPeerAs.IsNull() { + data.EnforceFirstPeerAs = types.BoolValue(value.Bool()) + } else { + data.EnforceFirstPeerAs = types.BoolNull() + } + if value := res.Get("asnotationDot"); value.Exists() && !data.UseDotNotation.IsNull() { + data.UseDotNotation = types.BoolValue(value.Bool()) + } else { + data.UseDotNotation = types.BoolNull() + } + if value := res.Get("aggregateTimer"); value.Exists() && !data.AggregateTimer.IsNull() { + data.AggregateTimer = types.Int64Value(value.Int()) + } else { + data.AggregateTimer = types.Int64Null() + } + if value := res.Get("bestPath.defaultLocalPreferenceValue"); value.Exists() && !data.DefaultLocalPreference.IsNull() { + data.DefaultLocalPreference = types.Int64Value(value.Int()) + } else { + data.DefaultLocalPreference = types.Int64Null() + } + if value := res.Get("bestPath.alwaysCompareMed"); value.Exists() && !data.CompareMedFromDifferentNeighbors.IsNull() { + data.CompareMedFromDifferentNeighbors = types.BoolValue(value.Bool()) + } else { + data.CompareMedFromDifferentNeighbors = types.BoolNull() + } + if value := res.Get("bestPath.deterministicMed"); value.Exists() && !data.CompareRouterIdInPath.IsNull() { + data.CompareRouterIdInPath = types.BoolValue(value.Bool()) + } else { + data.CompareRouterIdInPath = types.BoolNull() + } + if value := res.Get("bestPath.bestPathCompareRouterId"); value.Exists() && !data.PickBestMed.IsNull() { + data.PickBestMed = types.BoolValue(value.Bool()) + } else { + data.PickBestMed = types.BoolNull() + } + if value := res.Get("bestPath.bestPathMedMissingAsWorst"); value.Exists() && !data.MissingMedAsBest.IsNull() { + data.MissingMedAsBest = types.BoolValue(value.Bool()) + } else { + data.MissingMedAsBest = types.BoolNull() + } + if value := res.Get("bgptimers.keepAlive"); value.Exists() && !data.KeepaliveInterval.IsNull() { + data.KeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.KeepaliveInterval = types.Int64Null() + } + if value := res.Get("bgptimers.holdTime"); value.Exists() && !data.HoldTime.IsNull() { + data.HoldTime = types.Int64Value(value.Int()) + } else { + data.HoldTime = types.Int64Null() + } + if value := res.Get("bgptimers.minHoldTime"); value.Exists() && !data.MinHoldTime.IsNull() { + data.MinHoldTime = types.Int64Value(value.Int()) + } else { + data.MinHoldTime = types.Int64Null() + } + if value := res.Get("bgpNextHopTriggerEnable"); value.Exists() && !data.NextHopAddressTracking.IsNull() { + data.NextHopAddressTracking = types.BoolValue(value.Bool()) + } else { + data.NextHopAddressTracking = types.BoolNull() + } + if value := res.Get("bgpNextHopTriggerDelay"); value.Exists() && !data.NextHopDelayInterval.IsNull() { + data.NextHopDelayInterval = types.Int64Value(value.Int()) + } else { + data.NextHopDelayInterval = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestart"); value.Exists() && !data.GracefulRestart.IsNull() { + data.GracefulRestart = types.BoolValue(value.Bool()) + } else { + data.GracefulRestart = types.BoolNull() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartRestartTime"); value.Exists() && !data.GracefulRestartRestartTime.IsNull() { + data.GracefulRestartRestartTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartRestartTime = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartStalePathTime"); value.Exists() && !data.GracefulRestartStalePathTime.IsNull() { + data.GracefulRestartStalePathTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartStalePathTime = types.Int64Null() + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *DeviceBGPGeneralSettings) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Name.IsUnknown() { + if value := res.Get("name"); value.Exists() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_device_bgp_generel_settings.go b/internal/provider/model_fmc_device_bgp_generel_settings.go new file mode 100644 index 00000000..9b0b28a1 --- /dev/null +++ b/internal/provider/model_fmc_device_bgp_generel_settings.go @@ -0,0 +1,454 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type DeviceBGPGenerelSettings struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + DeviceId types.String `tfsdk:"device_id"` + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + AsNumber types.String `tfsdk:"as_number"` + RouterId types.String `tfsdk:"router_id"` + ScanningInterval types.Int64 `tfsdk:"scanning_interval"` + AsNoInPathAttribute types.Int64 `tfsdk:"as_no_in_path_attribute"` + LogNeighborChanges types.Bool `tfsdk:"log_neighbor_changes"` + TcpPathMtuDiscovery types.Bool `tfsdk:"tcp_path_mtu_discovery"` + ResetSessionUponFailover types.Bool `tfsdk:"reset_session_upon_failover"` + EnforceFirstPeerAs types.Bool `tfsdk:"enforce_first_peer_as"` + UseDotNotation types.Bool `tfsdk:"use_dot_notation"` + AggregateTimer types.Int64 `tfsdk:"aggregate_timer"` + DefaultLocalPreference types.Int64 `tfsdk:"default_local_preference"` + CompareMedFromDifferentNeighbors types.Bool `tfsdk:"compare_med_from_different_neighbors"` + CompareRouterIdInPath types.Bool `tfsdk:"compare_router_id_in_path"` + PickBestMed types.Bool `tfsdk:"pick_best_med"` + MissingMedAsBest types.Bool `tfsdk:"missing_med_as_best"` + KeepaliveInterval types.Int64 `tfsdk:"keepalive_interval"` + HoldTime types.Int64 `tfsdk:"hold_time"` + MinHoldTime types.Int64 `tfsdk:"min_hold_time"` + NextHopAddressTracking types.Bool `tfsdk:"next_hop_address_tracking"` + NextHopDelayInterval types.Int64 `tfsdk:"next_hop_delay_interval"` + GracefulRestart types.Bool `tfsdk:"graceful_restart"` + GracefulRestartRestartTime types.Int64 `tfsdk:"graceful_restart_restart_time"` + GracefulRestartStalePathTime types.Int64 `tfsdk:"graceful_restart_stale_path_time"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceBGPGenerelSettings) getPath() string { + return fmt.Sprintf("/api/fmc_config/v1/domain/{DOMAIN_UUID}/devices/devicerecords/%v/routing/bgpgeneralsettings", url.QueryEscape(data.DeviceId.ValueString())) +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceBGPGenerelSettings) toBody(ctx context.Context, state DeviceBGPGenerelSettings) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.AsNumber.IsNull() { + body, _ = sjson.Set(body, "asNumber", data.AsNumber.ValueString()) + } + if !data.RouterId.IsNull() { + body, _ = sjson.Set(body, "routerId", data.RouterId.ValueString()) + } + if !data.ScanningInterval.IsNull() { + body, _ = sjson.Set(body, "scanTime", data.ScanningInterval.ValueInt64()) + } + if !data.AsNoInPathAttribute.IsNull() { + body, _ = sjson.Set(body, "maxasLimit", data.AsNoInPathAttribute.ValueInt64()) + } + if !data.LogNeighborChanges.IsNull() { + body, _ = sjson.Set(body, "logNeighborChanges", data.LogNeighborChanges.ValueBool()) + } + if !data.TcpPathMtuDiscovery.IsNull() { + body, _ = sjson.Set(body, "transportPathMtuDiscovery", data.TcpPathMtuDiscovery.ValueBool()) + } + if !data.ResetSessionUponFailover.IsNull() { + body, _ = sjson.Set(body, "fastExternalFallOver", data.ResetSessionUponFailover.ValueBool()) + } + if !data.EnforceFirstPeerAs.IsNull() { + body, _ = sjson.Set(body, "enforceFirstAs", data.EnforceFirstPeerAs.ValueBool()) + } + if !data.UseDotNotation.IsNull() { + body, _ = sjson.Set(body, "asnotationDot", data.UseDotNotation.ValueBool()) + } + if !data.AggregateTimer.IsNull() { + body, _ = sjson.Set(body, "aggregateTimer", data.AggregateTimer.ValueInt64()) + } + if !data.DefaultLocalPreference.IsNull() { + body, _ = sjson.Set(body, "bestPath.defaultLocalPreferenceValue", data.DefaultLocalPreference.ValueInt64()) + } + if !data.CompareMedFromDifferentNeighbors.IsNull() { + body, _ = sjson.Set(body, "bestPath.alwaysCompareMed", data.CompareMedFromDifferentNeighbors.ValueBool()) + } + if !data.CompareRouterIdInPath.IsNull() { + body, _ = sjson.Set(body, "bestPath.deterministicMed", data.CompareRouterIdInPath.ValueBool()) + } + if !data.PickBestMed.IsNull() { + body, _ = sjson.Set(body, "bestPath.bestPathCompareRouterId", data.PickBestMed.ValueBool()) + } + if !data.MissingMedAsBest.IsNull() { + body, _ = sjson.Set(body, "bestPath.bestPathMedMissingAsWorst", data.MissingMedAsBest.ValueBool()) + } + if !data.KeepaliveInterval.IsNull() { + body, _ = sjson.Set(body, "bgptimers.keepAlive", data.KeepaliveInterval.ValueInt64()) + } + if !data.HoldTime.IsNull() { + body, _ = sjson.Set(body, "bgptimers.holdTime", data.HoldTime.ValueInt64()) + } + if !data.MinHoldTime.IsNull() { + body, _ = sjson.Set(body, "bgptimers.minHoldTime", data.MinHoldTime.ValueInt64()) + } + if !data.NextHopAddressTracking.IsNull() { + body, _ = sjson.Set(body, "bgpNextHopTriggerEnable", data.NextHopAddressTracking.ValueBool()) + } + if !data.NextHopDelayInterval.IsNull() { + body, _ = sjson.Set(body, "bgpNextHopTriggerDelay", data.NextHopDelayInterval.ValueInt64()) + } + if !data.GracefulRestart.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestart", data.GracefulRestart.ValueBool()) + } + if !data.GracefulRestartRestartTime.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestartRestartTime", data.GracefulRestartRestartTime.ValueInt64()) + } + if !data.GracefulRestartStalePathTime.IsNull() { + body, _ = sjson.Set(body, "bgpGracefulRestart.gracefulRestartStalePathTime", data.GracefulRestartStalePathTime.ValueInt64()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceBGPGenerelSettings) 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("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("asNumber"); value.Exists() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("routerId"); value.Exists() { + data.RouterId = types.StringValue(value.String()) + } else { + data.RouterId = types.StringNull() + } + if value := res.Get("scanTime"); value.Exists() { + data.ScanningInterval = types.Int64Value(value.Int()) + } else { + data.ScanningInterval = types.Int64Null() + } + if value := res.Get("maxasLimit"); value.Exists() { + data.AsNoInPathAttribute = types.Int64Value(value.Int()) + } else { + data.AsNoInPathAttribute = types.Int64Null() + } + if value := res.Get("logNeighborChanges"); value.Exists() { + data.LogNeighborChanges = types.BoolValue(value.Bool()) + } else { + data.LogNeighborChanges = types.BoolNull() + } + if value := res.Get("transportPathMtuDiscovery"); value.Exists() { + data.TcpPathMtuDiscovery = types.BoolValue(value.Bool()) + } else { + data.TcpPathMtuDiscovery = types.BoolNull() + } + if value := res.Get("fastExternalFallOver"); value.Exists() { + data.ResetSessionUponFailover = types.BoolValue(value.Bool()) + } else { + data.ResetSessionUponFailover = types.BoolNull() + } + if value := res.Get("enforceFirstAs"); value.Exists() { + data.EnforceFirstPeerAs = types.BoolValue(value.Bool()) + } else { + data.EnforceFirstPeerAs = types.BoolNull() + } + if value := res.Get("asnotationDot"); value.Exists() { + data.UseDotNotation = types.BoolValue(value.Bool()) + } else { + data.UseDotNotation = types.BoolNull() + } + if value := res.Get("aggregateTimer"); value.Exists() { + data.AggregateTimer = types.Int64Value(value.Int()) + } else { + data.AggregateTimer = types.Int64Null() + } + if value := res.Get("bestPath.defaultLocalPreferenceValue"); value.Exists() { + data.DefaultLocalPreference = types.Int64Value(value.Int()) + } else { + data.DefaultLocalPreference = types.Int64Null() + } + if value := res.Get("bestPath.alwaysCompareMed"); value.Exists() { + data.CompareMedFromDifferentNeighbors = types.BoolValue(value.Bool()) + } else { + data.CompareMedFromDifferentNeighbors = types.BoolNull() + } + if value := res.Get("bestPath.deterministicMed"); value.Exists() { + data.CompareRouterIdInPath = types.BoolValue(value.Bool()) + } else { + data.CompareRouterIdInPath = types.BoolNull() + } + if value := res.Get("bestPath.bestPathCompareRouterId"); value.Exists() { + data.PickBestMed = types.BoolValue(value.Bool()) + } else { + data.PickBestMed = types.BoolNull() + } + if value := res.Get("bestPath.bestPathMedMissingAsWorst"); value.Exists() { + data.MissingMedAsBest = types.BoolValue(value.Bool()) + } else { + data.MissingMedAsBest = types.BoolNull() + } + if value := res.Get("bgptimers.keepAlive"); value.Exists() { + data.KeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.KeepaliveInterval = types.Int64Null() + } + if value := res.Get("bgptimers.holdTime"); value.Exists() { + data.HoldTime = types.Int64Value(value.Int()) + } else { + data.HoldTime = types.Int64Null() + } + if value := res.Get("bgptimers.minHoldTime"); value.Exists() { + data.MinHoldTime = types.Int64Value(value.Int()) + } else { + data.MinHoldTime = types.Int64Null() + } + if value := res.Get("bgpNextHopTriggerEnable"); value.Exists() { + data.NextHopAddressTracking = types.BoolValue(value.Bool()) + } else { + data.NextHopAddressTracking = types.BoolNull() + } + if value := res.Get("bgpNextHopTriggerDelay"); value.Exists() { + data.NextHopDelayInterval = types.Int64Value(value.Int()) + } else { + data.NextHopDelayInterval = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestart"); value.Exists() { + data.GracefulRestart = types.BoolValue(value.Bool()) + } else { + data.GracefulRestart = types.BoolNull() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartRestartTime"); value.Exists() { + data.GracefulRestartRestartTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartRestartTime = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartStalePathTime"); value.Exists() { + data.GracefulRestartStalePathTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartStalePathTime = types.Int64Null() + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *DeviceBGPGenerelSettings) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("asNumber"); value.Exists() && !data.AsNumber.IsNull() { + data.AsNumber = types.StringValue(value.String()) + } else { + data.AsNumber = types.StringNull() + } + if value := res.Get("routerId"); value.Exists() && !data.RouterId.IsNull() { + data.RouterId = types.StringValue(value.String()) + } else { + data.RouterId = types.StringNull() + } + if value := res.Get("scanTime"); value.Exists() && !data.ScanningInterval.IsNull() { + data.ScanningInterval = types.Int64Value(value.Int()) + } else { + data.ScanningInterval = types.Int64Null() + } + if value := res.Get("maxasLimit"); value.Exists() && !data.AsNoInPathAttribute.IsNull() { + data.AsNoInPathAttribute = types.Int64Value(value.Int()) + } else { + data.AsNoInPathAttribute = types.Int64Null() + } + if value := res.Get("logNeighborChanges"); value.Exists() && !data.LogNeighborChanges.IsNull() { + data.LogNeighborChanges = types.BoolValue(value.Bool()) + } else { + data.LogNeighborChanges = types.BoolNull() + } + if value := res.Get("transportPathMtuDiscovery"); value.Exists() && !data.TcpPathMtuDiscovery.IsNull() { + data.TcpPathMtuDiscovery = types.BoolValue(value.Bool()) + } else { + data.TcpPathMtuDiscovery = types.BoolNull() + } + if value := res.Get("fastExternalFallOver"); value.Exists() && !data.ResetSessionUponFailover.IsNull() { + data.ResetSessionUponFailover = types.BoolValue(value.Bool()) + } else { + data.ResetSessionUponFailover = types.BoolNull() + } + if value := res.Get("enforceFirstAs"); value.Exists() && !data.EnforceFirstPeerAs.IsNull() { + data.EnforceFirstPeerAs = types.BoolValue(value.Bool()) + } else { + data.EnforceFirstPeerAs = types.BoolNull() + } + if value := res.Get("asnotationDot"); value.Exists() && !data.UseDotNotation.IsNull() { + data.UseDotNotation = types.BoolValue(value.Bool()) + } else { + data.UseDotNotation = types.BoolNull() + } + if value := res.Get("aggregateTimer"); value.Exists() && !data.AggregateTimer.IsNull() { + data.AggregateTimer = types.Int64Value(value.Int()) + } else { + data.AggregateTimer = types.Int64Null() + } + if value := res.Get("bestPath.defaultLocalPreferenceValue"); value.Exists() && !data.DefaultLocalPreference.IsNull() { + data.DefaultLocalPreference = types.Int64Value(value.Int()) + } else { + data.DefaultLocalPreference = types.Int64Null() + } + if value := res.Get("bestPath.alwaysCompareMed"); value.Exists() && !data.CompareMedFromDifferentNeighbors.IsNull() { + data.CompareMedFromDifferentNeighbors = types.BoolValue(value.Bool()) + } else { + data.CompareMedFromDifferentNeighbors = types.BoolNull() + } + if value := res.Get("bestPath.deterministicMed"); value.Exists() && !data.CompareRouterIdInPath.IsNull() { + data.CompareRouterIdInPath = types.BoolValue(value.Bool()) + } else { + data.CompareRouterIdInPath = types.BoolNull() + } + if value := res.Get("bestPath.bestPathCompareRouterId"); value.Exists() && !data.PickBestMed.IsNull() { + data.PickBestMed = types.BoolValue(value.Bool()) + } else { + data.PickBestMed = types.BoolNull() + } + if value := res.Get("bestPath.bestPathMedMissingAsWorst"); value.Exists() && !data.MissingMedAsBest.IsNull() { + data.MissingMedAsBest = types.BoolValue(value.Bool()) + } else { + data.MissingMedAsBest = types.BoolNull() + } + if value := res.Get("bgptimers.keepAlive"); value.Exists() && !data.KeepaliveInterval.IsNull() { + data.KeepaliveInterval = types.Int64Value(value.Int()) + } else { + data.KeepaliveInterval = types.Int64Null() + } + if value := res.Get("bgptimers.holdTime"); value.Exists() && !data.HoldTime.IsNull() { + data.HoldTime = types.Int64Value(value.Int()) + } else { + data.HoldTime = types.Int64Null() + } + if value := res.Get("bgptimers.minHoldTime"); value.Exists() && !data.MinHoldTime.IsNull() { + data.MinHoldTime = types.Int64Value(value.Int()) + } else { + data.MinHoldTime = types.Int64Null() + } + if value := res.Get("bgpNextHopTriggerEnable"); value.Exists() && !data.NextHopAddressTracking.IsNull() { + data.NextHopAddressTracking = types.BoolValue(value.Bool()) + } else { + data.NextHopAddressTracking = types.BoolNull() + } + if value := res.Get("bgpNextHopTriggerDelay"); value.Exists() && !data.NextHopDelayInterval.IsNull() { + data.NextHopDelayInterval = types.Int64Value(value.Int()) + } else { + data.NextHopDelayInterval = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestart"); value.Exists() && !data.GracefulRestart.IsNull() { + data.GracefulRestart = types.BoolValue(value.Bool()) + } else { + data.GracefulRestart = types.BoolNull() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartRestartTime"); value.Exists() && !data.GracefulRestartRestartTime.IsNull() { + data.GracefulRestartRestartTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartRestartTime = types.Int64Null() + } + if value := res.Get("bgpGracefulRestart.gracefulRestartStalePathTime"); value.Exists() && !data.GracefulRestartStalePathTime.IsNull() { + data.GracefulRestartStalePathTime = types.Int64Value(value.Int()) + } else { + data.GracefulRestartStalePathTime = types.Int64Null() + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *DeviceBGPGenerelSettings) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Name.IsUnknown() { + if value := res.Get("name"); value.Exists() { + data.Name = types.StringValue(value.String()) + } else { + data.Name = types.StringNull() + } + } + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk diff --git a/internal/provider/model_fmc_device_ha_pair_monitoring.go b/internal/provider/model_fmc_device_ha_pair_monitoring.go new file mode 100644 index 00000000..3d219200 --- /dev/null +++ b/internal/provider/model_fmc_device_ha_pair_monitoring.go @@ -0,0 +1,308 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "slices" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin types + +type DeviceHAPairMonitoring struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + DeviceId types.String `tfsdk:"device_id"` + Type types.String `tfsdk:"type"` + LogicalName types.String `tfsdk:"logical_name"` + MonitorInterface types.Bool `tfsdk:"monitor_interface"` + Ipv4ActiveAddress types.String `tfsdk:"ipv4_active_address"` + Ipv4StandbyAddress types.String `tfsdk:"ipv4_standby_address"` + Ipv4Netmask types.String `tfsdk:"ipv4_netmask"` + Ipv6Addresses []DeviceHAPairMonitoringIpv6Addresses `tfsdk:"ipv6_addresses"` +} + +type DeviceHAPairMonitoringIpv6Addresses struct { + ActiveAddress types.String `tfsdk:"active_address"` + StandbyAddress types.String `tfsdk:"standby_address"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceHAPairMonitoring) getPath() string { + return fmt.Sprintf("/api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs/%v/monitoredinterfaces", url.QueryEscape(data.DeviceId.ValueString())) +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceHAPairMonitoring) toBody(ctx context.Context, state DeviceHAPairMonitoring) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.LogicalName.IsNull() { + body, _ = sjson.Set(body, "name", data.LogicalName.ValueString()) + } + if !data.MonitorInterface.IsNull() { + body, _ = sjson.Set(body, "monitorForFailures", data.MonitorInterface.ValueBool()) + } + if !data.Ipv4StandbyAddress.IsNull() { + body, _ = sjson.Set(body, "ipv4Configuration.standbyIPv4Address", data.Ipv4StandbyAddress.ValueString()) + } + if len(data.Ipv6Addresses) > 0 { + body, _ = sjson.Set(body, "ipv6Configuration.ipv6ActiveStandbyPair", []interface{}{}) + for _, item := range data.Ipv6Addresses { + itemBody := "" + if !item.ActiveAddress.IsNull() { + itemBody, _ = sjson.Set(itemBody, "activeIPv6", item.ActiveAddress.ValueString()) + } + if !item.StandbyAddress.IsNull() { + itemBody, _ = sjson.Set(itemBody, "standbyIPv6", item.StandbyAddress.ValueString()) + } + body, _ = sjson.SetRaw(body, "ipv6Configuration.ipv6ActiveStandbyPair.-1", itemBody) + } + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceHAPairMonitoring) fromBody(ctx context.Context, res gjson.Result) { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("name"); value.Exists() { + data.LogicalName = types.StringValue(value.String()) + } else { + data.LogicalName = types.StringNull() + } + if value := res.Get("monitorForFailures"); value.Exists() { + data.MonitorInterface = types.BoolValue(value.Bool()) + } else { + data.MonitorInterface = types.BoolNull() + } + if value := res.Get("ipv4Configuration.activeIPv4Address"); value.Exists() { + data.Ipv4ActiveAddress = types.StringValue(value.String()) + } else { + data.Ipv4ActiveAddress = types.StringNull() + } + if value := res.Get("ipv4Configuration.standbyIPv4Address"); value.Exists() { + data.Ipv4StandbyAddress = types.StringValue(value.String()) + } else { + data.Ipv4StandbyAddress = types.StringNull() + } + if value := res.Get("ipv4Configuration.activeIPv4Mask"); value.Exists() { + data.Ipv4Netmask = types.StringValue(value.String()) + } else { + data.Ipv4Netmask = types.StringNull() + } + if value := res.Get("ipv6Configuration.ipv6ActiveStandbyPair"); value.Exists() { + data.Ipv6Addresses = make([]DeviceHAPairMonitoringIpv6Addresses, 0) + value.ForEach(func(k, res gjson.Result) bool { + parent := &data + data := DeviceHAPairMonitoringIpv6Addresses{} + if value := res.Get("activeIPv6"); value.Exists() { + data.ActiveAddress = types.StringValue(value.String()) + } else { + data.ActiveAddress = types.StringNull() + } + if value := res.Get("standbyIPv6"); value.Exists() { + data.StandbyAddress = types.StringValue(value.String()) + } else { + data.StandbyAddress = types.StringNull() + } + (*parent).Ipv6Addresses = append((*parent).Ipv6Addresses, data) + return true + }) + } +} + +// End of section. //template:end fromBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial + +// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to +// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might +// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the +// "managed" elements, instead of all elements. +func (data *DeviceHAPairMonitoring) fromBodyPartial(ctx context.Context, res gjson.Result) { + if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + if value := res.Get("name"); value.Exists() && !data.LogicalName.IsNull() { + data.LogicalName = types.StringValue(value.String()) + } else { + data.LogicalName = types.StringNull() + } + if value := res.Get("monitorForFailures"); value.Exists() && !data.MonitorInterface.IsNull() { + data.MonitorInterface = types.BoolValue(value.Bool()) + } else { + data.MonitorInterface = types.BoolNull() + } + if value := res.Get("ipv4Configuration.activeIPv4Address"); value.Exists() && !data.Ipv4ActiveAddress.IsNull() { + data.Ipv4ActiveAddress = types.StringValue(value.String()) + } else { + data.Ipv4ActiveAddress = types.StringNull() + } + if value := res.Get("ipv4Configuration.standbyIPv4Address"); value.Exists() && !data.Ipv4StandbyAddress.IsNull() { + data.Ipv4StandbyAddress = types.StringValue(value.String()) + } else { + data.Ipv4StandbyAddress = types.StringNull() + } + if value := res.Get("ipv4Configuration.activeIPv4Mask"); value.Exists() && !data.Ipv4Netmask.IsNull() { + data.Ipv4Netmask = types.StringValue(value.String()) + } else { + data.Ipv4Netmask = types.StringNull() + } + for i := 0; i < len(data.Ipv6Addresses); i++ { + keys := [...]string{"activeIPv6", "standbyIPv6"} + keyValues := [...]string{data.Ipv6Addresses[i].ActiveAddress.ValueString(), data.Ipv6Addresses[i].StandbyAddress.ValueString()} + + parent := &data + data := (*parent).Ipv6Addresses[i] + parentRes := &res + var res gjson.Result + + parentRes.Get("ipv6Configuration.ipv6ActiveStandbyPair").ForEach( + func(_, v gjson.Result) bool { + found := false + for ik := range keys { + if v.Get(keys[ik]).String() != keyValues[ik] { + found = false + break + } + found = true + } + if found { + res = v + return false + } + return true + }, + ) + if !res.Exists() { + tflog.Debug(ctx, fmt.Sprintf("removing Ipv6Addresses[%d] = %+v", + i, + (*parent).Ipv6Addresses[i], + )) + (*parent).Ipv6Addresses = slices.Delete((*parent).Ipv6Addresses, i, i+1) + i-- + + continue + } + if value := res.Get("activeIPv6"); value.Exists() && !data.ActiveAddress.IsNull() { + data.ActiveAddress = types.StringValue(value.String()) + } else { + data.ActiveAddress = types.StringNull() + } + if value := res.Get("standbyIPv6"); value.Exists() && !data.StandbyAddress.IsNull() { + data.StandbyAddress = types.StringValue(value.String()) + } else { + data.StandbyAddress = types.StringNull() + } + (*parent).Ipv6Addresses[i] = data + } +} + +// End of section. //template:end fromBodyPartial + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns + +// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. +// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). +func (data *DeviceHAPairMonitoring) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } + if data.Ipv4ActiveAddress.IsUnknown() { + if value := res.Get("ipv4Configuration.activeIPv4Address"); value.Exists() { + data.Ipv4ActiveAddress = types.StringValue(value.String()) + } else { + data.Ipv4ActiveAddress = types.StringNull() + } + } + if data.Ipv4Netmask.IsUnknown() { + if value := res.Get("ipv4Configuration.activeIPv4Mask"); value.Exists() { + data.Ipv4Netmask = types.StringValue(value.String()) + } else { + data.Ipv4Netmask = types.StringNull() + } + } +} + +// End of section. //template:end fromBodyUnknowns + +// Section below is generated&owned by "gen/generator.go". //template:begin Clone + +// End of section. //template:end Clone + +// Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk + +// End of section. //template:end toBodyNonBulk + +// toBodyPutDelete generates minimal required body to reset the resource to its default state. +func (data DeviceHAPairMonitoring) toBodyPutDelete(ctx context.Context, state DeviceHAPairMonitoring) string { + body := "" + body, _ = sjson.Set(body, "monitorForFailures", false) + if data.Ipv4ActiveAddress.ValueString() != "" { + body, _ = sjson.Set(body, "ipv4Configuration.activeIPv4Address", data.Ipv4ActiveAddress.ValueString()) + } + // There is no way of removing standby IPv6 via API now + //if len(data.Ipv6Addresses) > 0 { + // body, _ = sjson.Set(body, "ipv6Configuration.ipv6ActiveStandbyPair", []interface{}{}) + // for _, item := range data.Ipv6Addresses { + // itemBody := "" + // if !item.ActiveAddress.IsNull() { + // itemBody, _ = sjson.Set(itemBody, "activeIPv6", item.ActiveAddress.ValueString()) + // itemBody, _ = sjson.Set(itemBody, "standbyIPv6", "") + // } + // body, _ = sjson.SetRaw(body, "ipv6Configuration.ipv6ActiveStandbyPair.-1", itemBody) + // } + //} + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if !data.LogicalName.IsNull() { + body, _ = sjson.Set(body, "name", data.LogicalName.ValueString()) + } + return body +} diff --git a/internal/provider/model_fmc_network.go b/internal/provider/model_fmc_network.go index 67b5f6af..7db3644d 100644 --- a/internal/provider/model_fmc_network.go +++ b/internal/provider/model_fmc_network.go @@ -60,9 +60,6 @@ func (data Network) toBody(ctx context.Context, state Network) string { if !data.Name.IsNull() { body, _ = sjson.Set(body, "name", data.Name.ValueString()) } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) - } if !data.Description.IsNull() { body, _ = sjson.Set(body, "description", data.Description.ValueString()) } @@ -88,7 +85,7 @@ func (data *Network) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("Network") + data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() { data.Description = types.StringValue(value.String()) @@ -123,7 +120,7 @@ func (data *Network) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "Network" { + } else { data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() && !data.Description.IsNull() { @@ -150,6 +147,13 @@ func (data *Network) fromBodyPartial(ctx context.Context, res gjson.Result) { // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *Network) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/model_fmc_networks.go b/internal/provider/model_fmc_networks.go index 50760ee2..863b7292 100644 --- a/internal/provider/model_fmc_networks.go +++ b/internal/provider/model_fmc_networks.go @@ -80,9 +80,6 @@ func (data Networks) toBody(ctx context.Context, state Networks) string { if !item.Prefix.IsNull() { itemBody, _ = sjson.Set(itemBody, "value", item.Prefix.ValueString()) } - if !item.Type.IsNull() { - itemBody, _ = sjson.Set(itemBody, "type", item.Type.ValueString()) - } body, _ = sjson.SetRaw(body, "items.-1", itemBody) } } @@ -137,7 +134,7 @@ func (data *Networks) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("Network") + data.Type = types.StringNull() } (*parent).Items[k] = data } @@ -189,7 +186,7 @@ func (data *Networks) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "Network" { + } else { data.Type = types.StringNull() } (*parent).Items[i] = data @@ -230,6 +227,14 @@ func (data *Networks) fromBodyUnknowns(ctx context.Context, res gjson.Result) { } data.Items[i] = v } + if v := data.Items[i]; v.Type.IsUnknown() { + if value := r.Get("type"); value.Exists() { + v.Type = types.StringValue(value.String()) + } else { + v.Type = types.StringNull() + } + data.Items[i] = v + } } } diff --git a/internal/provider/model_fmc_port_group.go b/internal/provider/model_fmc_port_group.go index eac97b49..a3771e09 100644 --- a/internal/provider/model_fmc_port_group.go +++ b/internal/provider/model_fmc_port_group.go @@ -68,9 +68,6 @@ func (data PortGroup) toBody(ctx context.Context, state PortGroup) string { if !data.Name.IsNull() { body, _ = sjson.Set(body, "name", data.Name.ValueString()) } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) - } if !data.Description.IsNull() { body, _ = sjson.Set(body, "description", data.Description.ValueString()) } @@ -106,7 +103,7 @@ func (data *PortGroup) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("PortObjectGroup") + data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() { data.Description = types.StringValue(value.String()) @@ -155,7 +152,7 @@ func (data *PortGroup) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "PortObjectGroup" { + } else { data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() && !data.Description.IsNull() { @@ -225,6 +222,13 @@ func (data *PortGroup) fromBodyPartial(ctx context.Context, res gjson.Result) { // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *PortGroup) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/model_fmc_port_groups.go b/internal/provider/model_fmc_port_groups.go index 9a6e74e3..c9dfc552 100644 --- a/internal/provider/model_fmc_port_groups.go +++ b/internal/provider/model_fmc_port_groups.go @@ -77,9 +77,6 @@ func (data PortGroups) toBody(ctx context.Context, state PortGroups) string { if !item.Id.IsNull() && !item.Id.IsUnknown() { itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString()) } - if !item.Type.IsNull() { - itemBody, _ = sjson.Set(itemBody, "type", item.Type.ValueString()) - } if !item.Description.IsNull() { itemBody, _ = sjson.Set(itemBody, "description", item.Description.ValueString()) } @@ -138,7 +135,7 @@ func (data *PortGroups) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("PortObjectGroup") + data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() { data.Description = types.StringValue(value.String()) @@ -204,7 +201,7 @@ func (data *PortGroups) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "PortObjectGroup" { + } else { data.Type = types.StringNull() } if value := res.Get("description"); value.Exists() && !data.Description.IsNull() { @@ -303,6 +300,14 @@ func (data *PortGroups) fromBodyUnknowns(ctx context.Context, res gjson.Result) } data.Items[i] = v } + if v := data.Items[i]; v.Type.IsUnknown() { + if value := r.Get("type"); value.Exists() { + v.Type = types.StringValue(value.String()) + } else { + v.Type = types.StringNull() + } + data.Items[i] = v + } } } diff --git a/internal/provider/model_fmc_security_zone.go b/internal/provider/model_fmc_security_zone.go index 4aab8c0c..e551d103 100644 --- a/internal/provider/model_fmc_security_zone.go +++ b/internal/provider/model_fmc_security_zone.go @@ -34,7 +34,7 @@ type SecurityZone struct { Id types.String `tfsdk:"id"` Domain types.String `tfsdk:"domain"` Name types.String `tfsdk:"name"` - InterfaceMode types.String `tfsdk:"interface_mode"` + InterfaceType types.String `tfsdk:"interface_type"` Type types.String `tfsdk:"type"` } @@ -58,11 +58,8 @@ func (data SecurityZone) toBody(ctx context.Context, state SecurityZone) string if !data.Name.IsNull() { body, _ = sjson.Set(body, "name", data.Name.ValueString()) } - if !data.InterfaceMode.IsNull() { - body, _ = sjson.Set(body, "interfaceMode", data.InterfaceMode.ValueString()) - } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) + if !data.InterfaceType.IsNull() { + body, _ = sjson.Set(body, "interfaceMode", data.InterfaceType.ValueString()) } return body } @@ -78,14 +75,14 @@ func (data *SecurityZone) fromBody(ctx context.Context, res gjson.Result) { data.Name = types.StringNull() } if value := res.Get("interfaceMode"); value.Exists() { - data.InterfaceMode = types.StringValue(value.String()) + data.InterfaceType = types.StringValue(value.String()) } else { - data.InterfaceMode = types.StringNull() + data.InterfaceType = types.StringNull() } if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SecurityZone") + data.Type = types.StringNull() } } @@ -103,14 +100,14 @@ func (data *SecurityZone) fromBodyPartial(ctx context.Context, res gjson.Result) } else { data.Name = types.StringNull() } - if value := res.Get("interfaceMode"); value.Exists() && !data.InterfaceMode.IsNull() { - data.InterfaceMode = types.StringValue(value.String()) + if value := res.Get("interfaceMode"); value.Exists() && !data.InterfaceType.IsNull() { + data.InterfaceType = types.StringValue(value.String()) } else { - data.InterfaceMode = types.StringNull() + data.InterfaceType = types.StringNull() } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SecurityZone" { + } else { data.Type = types.StringNull() } } @@ -122,6 +119,13 @@ func (data *SecurityZone) fromBodyPartial(ctx context.Context, res gjson.Result) // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *SecurityZone) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/model_fmc_security_zones.go b/internal/provider/model_fmc_security_zones.go index 457b8565..c40190ce 100644 --- a/internal/provider/model_fmc_security_zones.go +++ b/internal/provider/model_fmc_security_zones.go @@ -41,7 +41,7 @@ type SecurityZones struct { type SecurityZonesItems struct { Id types.String `tfsdk:"id"` - InterfaceMode types.String `tfsdk:"interface_mode"` + InterfaceType types.String `tfsdk:"interface_type"` Type types.String `tfsdk:"type"` } @@ -69,11 +69,8 @@ func (data SecurityZones) toBody(ctx context.Context, state SecurityZones) strin if !item.Id.IsNull() && !item.Id.IsUnknown() { itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString()) } - if !item.InterfaceMode.IsNull() { - itemBody, _ = sjson.Set(itemBody, "interfaceMode", item.InterfaceMode.ValueString()) - } - if !item.Type.IsNull() { - itemBody, _ = sjson.Set(itemBody, "type", item.Type.ValueString()) + if !item.InterfaceType.IsNull() { + itemBody, _ = sjson.Set(itemBody, "interfaceMode", item.InterfaceType.ValueString()) } body, _ = sjson.SetRaw(body, "items.-1", itemBody) } @@ -112,14 +109,14 @@ func (data *SecurityZones) fromBody(ctx context.Context, res gjson.Result) { data.Id = types.StringNull() } if value := res.Get("interfaceMode"); value.Exists() { - data.InterfaceMode = types.StringValue(value.String()) + data.InterfaceType = types.StringValue(value.String()) } else { - data.InterfaceMode = types.StringNull() + data.InterfaceType = types.StringNull() } if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SecurityZone") + data.Type = types.StringNull() } (*parent).Items[k] = data } @@ -154,14 +151,14 @@ func (data *SecurityZones) fromBodyPartial(ctx context.Context, res gjson.Result } else { data.Id = types.StringNull() } - if value := res.Get("interfaceMode"); value.Exists() && !data.InterfaceMode.IsNull() { - data.InterfaceMode = types.StringValue(value.String()) + if value := res.Get("interfaceMode"); value.Exists() && !data.InterfaceType.IsNull() { + data.InterfaceType = types.StringValue(value.String()) } else { - data.InterfaceMode = types.StringNull() + data.InterfaceType = types.StringNull() } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SecurityZone" { + } else { data.Type = types.StringNull() } (*parent).Items[i] = data @@ -202,6 +199,14 @@ func (data *SecurityZones) fromBodyUnknowns(ctx context.Context, res gjson.Resul } data.Items[i] = v } + if v := data.Items[i]; v.Type.IsUnknown() { + if value := r.Get("type"); value.Exists() { + v.Type = types.StringValue(value.String()) + } else { + v.Type = types.StringNull() + } + data.Items[i] = v + } } } diff --git a/internal/provider/model_fmc_snmp_alert.go b/internal/provider/model_fmc_snmp_alert.go index eae10335..b83f2e34 100644 --- a/internal/provider/model_fmc_snmp_alert.go +++ b/internal/provider/model_fmc_snmp_alert.go @@ -57,9 +57,6 @@ func (data SNMPAlert) toBody(ctx context.Context, state SNMPAlert) string { if !data.Name.IsNull() { body, _ = sjson.Set(body, "name", data.Name.ValueString()) } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) - } return body } @@ -76,7 +73,7 @@ func (data *SNMPAlert) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SNMPAlert") + data.Type = types.StringNull() } } @@ -96,7 +93,7 @@ func (data *SNMPAlert) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SNMPAlert" { + } else { data.Type = types.StringNull() } } @@ -108,6 +105,13 @@ func (data *SNMPAlert) fromBodyPartial(ctx context.Context, res gjson.Result) { // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *SNMPAlert) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/model_fmc_snmp_alerts.go b/internal/provider/model_fmc_snmp_alerts.go index 17e7cc3c..b1e431b7 100644 --- a/internal/provider/model_fmc_snmp_alerts.go +++ b/internal/provider/model_fmc_snmp_alerts.go @@ -68,9 +68,6 @@ func (data SNMPAlerts) toBody(ctx context.Context, state SNMPAlerts) string { if !item.Id.IsNull() && !item.Id.IsUnknown() { itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString()) } - if !item.Type.IsNull() { - itemBody, _ = sjson.Set(itemBody, "type", item.Type.ValueString()) - } body, _ = sjson.SetRaw(body, "items.-1", itemBody) } } @@ -110,7 +107,7 @@ func (data *SNMPAlerts) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SNMPAlert") + data.Type = types.StringNull() } (*parent).Items[k] = data } @@ -147,7 +144,7 @@ func (data *SNMPAlerts) fromBodyPartial(ctx context.Context, res gjson.Result) { } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SNMPAlert" { + } else { data.Type = types.StringNull() } (*parent).Items[i] = data @@ -188,6 +185,14 @@ func (data *SNMPAlerts) fromBodyUnknowns(ctx context.Context, res gjson.Result) } data.Items[i] = v } + if v := data.Items[i]; v.Type.IsUnknown() { + if value := r.Get("type"); value.Exists() { + v.Type = types.StringValue(value.String()) + } else { + v.Type = types.StringNull() + } + data.Items[i] = v + } } } diff --git a/internal/provider/model_fmc_syslog_alert.go b/internal/provider/model_fmc_syslog_alert.go index 0678f70e..d6a332c2 100644 --- a/internal/provider/model_fmc_syslog_alert.go +++ b/internal/provider/model_fmc_syslog_alert.go @@ -57,9 +57,6 @@ func (data SyslogAlert) toBody(ctx context.Context, state SyslogAlert) string { if !data.Name.IsNull() { body, _ = sjson.Set(body, "name", data.Name.ValueString()) } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) - } return body } @@ -76,7 +73,7 @@ func (data *SyslogAlert) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SyslogAlert") + data.Type = types.StringNull() } } @@ -96,7 +93,7 @@ func (data *SyslogAlert) fromBodyPartial(ctx context.Context, res gjson.Result) } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SyslogAlert" { + } else { data.Type = types.StringNull() } } @@ -108,6 +105,13 @@ func (data *SyslogAlert) fromBodyPartial(ctx context.Context, res gjson.Result) // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *SyslogAlert) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/model_fmc_syslog_alerts.go b/internal/provider/model_fmc_syslog_alerts.go index 00cbf6f0..7c57195d 100644 --- a/internal/provider/model_fmc_syslog_alerts.go +++ b/internal/provider/model_fmc_syslog_alerts.go @@ -68,9 +68,6 @@ func (data SyslogAlerts) toBody(ctx context.Context, state SyslogAlerts) string if !item.Id.IsNull() && !item.Id.IsUnknown() { itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString()) } - if !item.Type.IsNull() { - itemBody, _ = sjson.Set(itemBody, "type", item.Type.ValueString()) - } body, _ = sjson.SetRaw(body, "items.-1", itemBody) } } @@ -110,7 +107,7 @@ func (data *SyslogAlerts) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("SyslogAlert") + data.Type = types.StringNull() } (*parent).Items[k] = data } @@ -147,7 +144,7 @@ func (data *SyslogAlerts) fromBodyPartial(ctx context.Context, res gjson.Result) } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "SyslogAlert" { + } else { data.Type = types.StringNull() } (*parent).Items[i] = data @@ -188,6 +185,14 @@ func (data *SyslogAlerts) fromBodyUnknowns(ctx context.Context, res gjson.Result } data.Items[i] = v } + if v := data.Items[i]; v.Type.IsUnknown() { + if value := r.Get("type"); value.Exists() { + v.Type = types.StringValue(value.String()) + } else { + v.Type = types.StringNull() + } + data.Items[i] = v + } } } diff --git a/internal/provider/model_fmc_variable_set.go b/internal/provider/model_fmc_variable_set.go index 5dbe90ae..270af1f6 100644 --- a/internal/provider/model_fmc_variable_set.go +++ b/internal/provider/model_fmc_variable_set.go @@ -61,9 +61,6 @@ func (data VariableSet) toBody(ctx context.Context, state VariableSet) string { if !data.Description.IsNull() { body, _ = sjson.Set(body, "description", data.Description.ValueString()) } - if !data.Type.IsNull() { - body, _ = sjson.Set(body, "type", data.Type.ValueString()) - } return body } @@ -85,7 +82,7 @@ func (data *VariableSet) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("type"); value.Exists() { data.Type = types.StringValue(value.String()) } else { - data.Type = types.StringValue("VariableSet") + data.Type = types.StringNull() } } @@ -110,7 +107,7 @@ func (data *VariableSet) fromBodyPartial(ctx context.Context, res gjson.Result) } if value := res.Get("type"); value.Exists() && !data.Type.IsNull() { data.Type = types.StringValue(value.String()) - } else if data.Type.ValueString() != "VariableSet" { + } else { data.Type = types.StringNull() } } @@ -122,6 +119,13 @@ func (data *VariableSet) fromBodyPartial(ctx context.Context, res gjson.Result) // fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON. // Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default). func (data *VariableSet) fromBodyUnknowns(ctx context.Context, res gjson.Result) { + if data.Type.IsUnknown() { + if value := res.Get("type"); value.Exists() { + data.Type = types.StringValue(value.String()) + } else { + data.Type = types.StringNull() + } + } } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/provider.go b/internal/provider/provider.go index da76c28d..ebc832df 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -293,8 +293,13 @@ func (p *FmcProvider) Configure(ctx context.Context, req provider.ConfigureReque func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ NewAccessControlPolicyResource, + NewBFDTemplateResource, NewDeviceResource, + NewDeviceBFDResource, + NewDeviceBGPResource, + NewDeviceBGPGeneralSettingsResource, NewDeviceEtherChannelInterfaceResource, + NewDeviceHAPairMonitoringResource, NewDeviceIPv4StaticRouteResource, NewDeviceIPv6StaticRouteResource, NewDevicePhysicalInterfaceResource, @@ -346,8 +351,13 @@ func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource func (p *FmcProvider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ NewAccessControlPolicyDataSource, + NewBFDTemplateDataSource, NewDeviceDataSource, + NewDeviceBFDDataSource, + NewDeviceBGPDataSource, + NewDeviceBGPGeneralSettingsDataSource, NewDeviceEtherChannelInterfaceDataSource, + NewDeviceHAPairMonitoringDataSource, NewDeviceIPv4StaticRouteDataSource, NewDeviceIPv6StaticRouteDataSource, NewDevicePhysicalInterfaceDataSource, diff --git a/internal/provider/resource_fmc_bfd_template.go b/internal/provider/resource_fmc_bfd_template.go new file mode 100644 index 00000000..90e51c46 --- /dev/null +++ b/internal/provider/resource_fmc_bfd_template.go @@ -0,0 +1,350 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "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-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &BFDTemplateResource{} + _ resource.ResourceWithImportState = &BFDTemplateResource{} +) + +func NewBFDTemplateResource() resource.Resource { + return &BFDTemplateResource{} +} + +type BFDTemplateResource struct { + client *fmc.Client +} + +func (r *BFDTemplateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_bfd_template" +} + +func (r *BFDTemplateResource) 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 BFD Template.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("The name of the bfd template object.").String, + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'BFDTemplate'.").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("The hop type.").AddStringEnumDescription("SINGLE_HOP", "MULTI_HOP").String, + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("SINGLE_HOP", "MULTI_HOP"), + }, + }, + "echo": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Enables/disables BFD echo.").AddStringEnumDescription("ENABLED", "DISABLED").String, + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("ENABLED", "DISABLED"), + }, + }, + "interval_time": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Interval unit of measurement of time.").AddStringEnumDescription("MILLISECONDS", "MICROSECONDS", "NONE").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("MILLISECONDS", "MICROSECONDS", "NONE"), + }, + }, + "min_transmit": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Minimum Transmit unit value.").AddIntegerRangeDescription(50, 999000).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(50, 999000), + }, + }, + "tx_rx_multiplier": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Multipler value.").AddIntegerRangeDescription(3, 50).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(3, 50), + }, + }, + "min_receive": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Minimum Receive unit value in ranges: 50-999 miliseconds, 50000-999000 microseconds").AddIntegerRangeDescription(50, 999000).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(50, 999000), + }, + }, + "authentication_password": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Password for BFD Authentication (1-24 characters)").String, + Optional: true, + }, + "authentication_key_id": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Authentication Key ID").AddIntegerRangeDescription(0, 255).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 255), + }, + }, + "authentication_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Authentication types").AddStringEnumDescription("MD5", "METICULOUSMD5", "METICULOUSSHA1", "SHA1", "NONE").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("MD5", "METICULOUSMD5", "METICULOUSSHA1", "SHA1", "NONE"), + }, + }, + }, + } +} + +func (r *BFDTemplateResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *BFDTemplateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan BFDTemplate + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, BFDTemplate{}) + res, err := r.client.Post(plan.getPath(), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *BFDTemplateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state BFDTemplate + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *BFDTemplateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state BFDTemplate + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +// Section below is generated&owned by "gen/generator.go". //template:begin delete + +func (r *BFDTemplateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state BFDTemplate + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...) + 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.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// End of section. //template:end delete + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *BFDTemplateResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_bfd_template_test.go b/internal/provider/resource_fmc_bfd_template_test.go new file mode 100644 index 00000000..6e89f67a --- /dev/null +++ b/internal/provider/resource_fmc_bfd_template_test.go @@ -0,0 +1,105 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcBFDTemplate(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "name", "BFD_Template1")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_bfd_template.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "echo", "ENABLED")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "interval_time", "MILLISECONDS")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "min_transmit", "300")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "tx_rx_multiplier", "3")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "min_receive", "300")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "authentication_password", "Cisco123!")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "authentication_key_id", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bfd_template.test", "authentication_type", "MD5")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcBFDTemplateConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcBFDTemplateConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + steps = append(steps, resource.TestStep{ + ResourceName: "fmc_bfd_template.test", + ImportState: true, + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcBFDTemplateConfig_minimum() string { + config := `resource "fmc_bfd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcBFDTemplateConfig_all() string { + config := `resource "fmc_bfd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 300` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 300` + "\n" + config += ` authentication_password = "Cisco123!"` + "\n" + config += ` authentication_key_id = 1` + "\n" + config += ` authentication_type = "MD5"` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_bgd_template.go b/internal/provider/resource_fmc_bgd_template.go new file mode 100644 index 00000000..dce160a8 --- /dev/null +++ b/internal/provider/resource_fmc_bgd_template.go @@ -0,0 +1,329 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "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/int64default" + "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-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &BGDTemplateResource{} + _ resource.ResourceWithImportState = &BGDTemplateResource{} +) + +func NewBGDTemplateResource() resource.Resource { + return &BGDTemplateResource{} +} + +type BGDTemplateResource struct { + client *fmc.Client +} + +func (r *BGDTemplateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_bgd_template" +} + +func (r *BGDTemplateResource) 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 BGD Template.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("The name of the host object.").String, + Required: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'BFDTemplate'.").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("SINGLE_HOP | MULTI_HOP").String, + Required: true, + }, + "echo": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("(ENABLED | DISABLED)").String, + Required: true, + }, + "interval_time": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("(MILLISECONDS | MICROSECONDS | NONE)").String, + Required: true, + }, + "min_transmit": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Minimum Transmit").AddIntegerRangeDescription(50000, 999000).AddDefaultValueDescription("100000").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(50000, 999000), + }, + Default: int64default.StaticInt64(100000), + }, + "tx_rx_multiplier": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Multipler").AddIntegerRangeDescription(3, 50).AddDefaultValueDescription("3").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(3, 50), + }, + Default: int64default.StaticInt64(3), + }, + "min_receive": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Minimum Receive").AddIntegerRangeDescription(50000, 999000).AddDefaultValueDescription("100000").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(50000, 999000), + }, + Default: int64default.StaticInt64(100000), + }, + }, + } +} + +func (r *BGDTemplateResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *BGDTemplateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan BGDTemplate + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, BGDTemplate{}) + res, err := r.client.Post(plan.getPath(), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *BGDTemplateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state BGDTemplate + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *BGDTemplateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state BGDTemplate + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +// Section below is generated&owned by "gen/generator.go". //template:begin delete + +func (r *BGDTemplateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state BGDTemplate + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...) + 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.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// End of section. //template:end delete + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *BGDTemplateResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_bgd_template_test.go b/internal/provider/resource_fmc_bgd_template_test.go new file mode 100644 index 00000000..dde82b68 --- /dev/null +++ b/internal/provider/resource_fmc_bgd_template_test.go @@ -0,0 +1,99 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcBGDTemplate(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "name", "BFD_Template1")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_bgd_template.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "echo", "ENABLED")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "interval_time", "MILLISECONDS")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "min_transmit", "100000")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "tx_rx_multiplier", "3")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_bgd_template.test", "min_receive", "100000")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcBGDTemplateConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcBGDTemplateConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + steps = append(steps, resource.TestStep{ + ResourceName: "fmc_bgd_template.test", + ImportState: true, + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcBGDTemplateConfig_minimum() string { + config := `resource "fmc_bgd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcBGDTemplateConfig_all() string { + config := `resource "fmc_bgd_template" "test" {` + "\n" + config += ` name = "BFD_Template1"` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` echo = "ENABLED"` + "\n" + config += ` interval_time = "MILLISECONDS"` + "\n" + config += ` min_transmit = 100000` + "\n" + config += ` tx_rx_multiplier = 3` + "\n" + config += ` min_receive = 100000` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_device.go b/internal/provider/resource_fmc_device.go index 754b9f39..07fc1326 100644 --- a/internal/provider/resource_fmc_device.go +++ b/internal/provider/resource_fmc_device.go @@ -113,9 +113,6 @@ func (r *DeviceResource) Schema(ctx context.Context, req resource.SchemaRequest, Optional: true, Computed: true, Default: stringdefault.StaticString("Device"), - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, }, "access_policy_id": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("The UUID of the assigned access control policy. For example `fmc_access_control_policy.example.id`.").String, diff --git a/internal/provider/resource_fmc_device_bfd.go b/internal/provider/resource_fmc_device_bfd.go new file mode 100644 index 00000000..8a3b2f14 --- /dev/null +++ b/internal/provider/resource_fmc_device_bfd.go @@ -0,0 +1,340 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "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/int64default" + "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-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &DeviceBFDResource{} + _ resource.ResourceWithImportState = &DeviceBFDResource{} +) + +func NewDeviceBFDResource() resource.Resource { + return &DeviceBFDResource{} +} + +type DeviceBFDResource struct { + client *fmc.Client +} + +func (r *DeviceBFDResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bfd" +} + +func (r *DeviceBFDResource) 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 Device BFD.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("UUID of the parent device (fmc_device.example.id).").String, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'BFDPolicy'").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "hop_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Hop type.").AddStringEnumDescription("SINGLE_HOP", "MULTI_HOP").String, + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("SINGLE_HOP", "MULTI_HOP"), + }, + }, + "bfd_template_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of the BFD Template").String, + Required: true, + }, + "interface_logical_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Logical Name of the interface of BFD assignment if SINGLE_HOP selected.").String, + Optional: true, + }, + "destination_host_object_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("The ID of the destination host object if MULTI_HOP selected.").String, + Optional: true, + }, + "source_host_object_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("The ID of the source host object if MULTI_HOP selected.").String, + Optional: true, + }, + "interface_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of the interface of BFD assignment if SINGLE_HOP selected.").String, + Optional: true, + }, + "slow_timer": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Slow Timer value in range: 1000-30000, default: 1000").AddIntegerRangeDescription(1000, 30000).AddDefaultValueDescription("1000").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1000, 30000), + }, + Default: int64default.StaticInt64(1000), + }, + }, + } +} + +func (r *DeviceBFDResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *DeviceBFDResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceBFD + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, DeviceBFD{}) + res, err := r.client.Post(plan.getPath(), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *DeviceBFDResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceBFD + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *DeviceBFDResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceBFD + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +// Section below is generated&owned by "gen/generator.go". //template:begin delete + +func (r *DeviceBFDResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceBFD + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...) + 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.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// End of section. //template:end delete + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *DeviceBFDResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + idParts := strings.Split(req.ID, ",") + + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), + ) + return + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("device_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_device_bfd_test.go b/internal/provider/resource_fmc_device_bfd_test.go new file mode 100644 index 00000000..5646ad9e --- /dev/null +++ b/internal/provider/resource_fmc_device_bfd_test.go @@ -0,0 +1,104 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcDeviceBFD(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bfd.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "hop_type", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "bfd_template_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "interface_logical_name", "outside")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "destination_host_object_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "source_host_object_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "interface_id", "76d24097-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bfd.test", "slow_timer", "")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBFDPrerequisitesConfig + testAccFmcDeviceBFDConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBFDPrerequisitesConfig + testAccFmcDeviceBFDConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccFmcDeviceBFDPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcDeviceBFDConfig_minimum() string { + config := `resource "fmc_device_bfd" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcDeviceBFDConfig_all() string { + config := `resource "fmc_device_bfd" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` hop_type = "SINGLE_HOP"` + "\n" + config += ` bfd_template_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_logical_name = "outside"` + "\n" + config += ` destination_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` source_host_object_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` interface_id = "76d24097-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` slow_timer = ` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_device_bgp.go b/internal/provider/resource_fmc_device_bgp.go new file mode 100644 index 00000000..548352f3 --- /dev/null +++ b/internal/provider/resource_fmc_device_bgp.go @@ -0,0 +1,812 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "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/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &DeviceBGPResource{} + _ resource.ResourceWithImportState = &DeviceBGPResource{} +) + +func NewDeviceBGPResource() resource.Resource { + return &DeviceBGPResource{} +} + +type DeviceBGPResource struct { + client *fmc.Client +} + +func (r *DeviceBGPResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bgp" +} + +func (r *DeviceBGPResource) 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("Under BGP General Settings, BGP has to be enabled and AS Number assigned first.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("UUID of the parent device (fmc_device.example.id).").String, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Name of the object; this is always 'bgp'").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this is always 'bgp'").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "as_number": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Autonomus System (AS) Number").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ipv4_address_family_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ipv4_learned_route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Learned Route Map ID").String, + Optional: true, + }, + "ipv4_default_information_orginate": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Generate default routes").String, + Optional: true, + }, + "ipv4_auto_aummary": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Summarize subnet routes into network level routes").String, + Optional: true, + }, + "ipv4_bgp_supress_inactive": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Suppresing advertise inactive routes").String, + Optional: true, + }, + "ipv4_synchronization": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Synchronize between BGP and IGP systems").String, + Optional: true, + }, + "ipv4_bgp_redistribute_internal": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Redistribute IBGP into IGP. (Use filtering to limit the number of prefixes that are redistributed)").String, + Optional: true, + }, + "ipv4_external_distance": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Administrative route distance for external routes").AddIntegerRangeDescription(1, 255).AddDefaultValueDescription("20").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 255), + }, + Default: int64default.StaticInt64(20), + }, + "ipv4_internal_distance": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Administrative route distance for internal routes").AddIntegerRangeDescription(1, 255).AddDefaultValueDescription("200").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 255), + }, + Default: int64default.StaticInt64(200), + }, + "ipv4_local_distance": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Administrative route distance for local routes").AddIntegerRangeDescription(1, 255).AddDefaultValueDescription("200").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 255), + }, + Default: int64default.StaticInt64(200), + }, + "ipv4_forward_packets_over_multipath_ibgp": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Number of paths to use for IBGP").AddIntegerRangeDescription(1, 8).AddDefaultValueDescription("1").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 8), + }, + Default: int64default.StaticInt64(1), + }, + "ipv4_forward_packets_over_multipath_ebgp": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Number of paths to use for EBGP").AddIntegerRangeDescription(1, 8).AddDefaultValueDescription("1").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 8), + }, + Default: int64default.StaticInt64(1), + }, + "ipv4_neighbors": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "neighbor_address": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("IP address of the BGP neighbor").String, + Optional: true, + }, + "neighbor_remote_as": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("AS number of the BGP neighbor").String, + Optional: true, + }, + "neighbor_bfd": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("BFD Fallover").AddStringEnumDescription("SINGLE_HOP", "MULTI_HOP", "AUTO_DETECT_HOP", "NONE").AddDefaultValueDescription("NONE").String, + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOf("SINGLE_HOP", "MULTI_HOP", "AUTO_DETECT_HOP", "NONE"), + }, + Default: stringdefault.StaticString("NONE"), + }, + "update_source_interface_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Interface ID for the update source").String, + Optional: true, + }, + "enable_address_family": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Enable IPv4 address family").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_shutdown": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Shutdown administratively").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_description": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Description of the neighbor").String, + Optional: true, + }, + "neighbor_filter_access_lists": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "access_list_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Access List ID").String, + Optional: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filter direction").AddStringEnumDescription("IN", "OUT").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("IN", "OUT"), + }, + }, + }, + }, + }, + "neighbor_filter_route_map_lists": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Route Map ID").String, + Optional: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filter direction").AddStringEnumDescription("IN", "OUT").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("IN", "OUT"), + }, + }, + }, + }, + }, + "neighbor_filter_prefix_lists": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "prefix_list_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Route Map ID").String, + Optional: true, + }, + "update_direction": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filter direction").AddStringEnumDescription("IN", "OUT").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("IN", "OUT"), + }, + }, + }, + }, + }, + "neighbor_filter_as_path_lists": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "update_direction": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filter direction").AddStringEnumDescription("IN", "OUT").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("IN", "OUT"), + }, + }, + "as_path_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("AS Path ID").String, + Optional: true, + }, + }, + }, + }, + "neighbor_filter_max_prefix": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Maximum number of prefixes allowed from the neighbor").AddIntegerRangeDescription(1, 2147483647).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 2147483647), + }, + }, + "neighbor_filter_warning_only": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Give only warning message when prefix limit exceeded or terminate peering when prefix limit is exceeded.").String, + Optional: true, + }, + "neighbor_filter_threshold_value": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Threshold value for the maximum number of prefixes allowed from the neighbor").AddIntegerRangeDescription(1, 100).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 100), + }, + }, + "neighbor_filter_restart_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Time interval to restart the maximum prefix limit in Minutes").AddIntegerRangeDescription(1, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 65535), + }, + }, + "neighbor_routes_advertisement_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Time interval to advertise routes in seconds").AddIntegerRangeDescription(0, 600).AddDefaultValueDescription("0").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(0, 600), + }, + Default: int64default.StaticInt64(0), + }, + "neighbor_routes_remove_private_as": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Remove private AS numbers from outgoing routing updates").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_generate_default_route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Generate default routes - Route Map").String, + Optional: true, + }, + "neighbor_routes_advertise_map_use_exist": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Use Exist Map or Non-Exist Map").String, + Optional: true, + }, + "neighbor_routes_advertise_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Specified route maps are advertised when the prefix exists in the Advertise Map and Exist Map.").String, + Optional: true, + }, + "neighbor_routes_advertise_exist_nonexist_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Specified route maps are advertised when the prefix exists only in the Advertise Map.").String, + Optional: true, + }, + "neighbor_keepalive_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Time interval to send keepalive messages in seconds").AddIntegerRangeDescription(0, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 65535), + }, + }, + "neighbor_hold_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Time interval to hold the neighbor in seconds").AddIntegerRangeDescription(3, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(3, 65535), + }, + }, + "neighbor_min_hold_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Minimum hold time in seconds").AddIntegerRangeDescription(3, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(3, 65535), + }, + }, + "neighbor_authentication_password": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Setting password enables authentication.").String, + Optional: true, + }, + "neighbor_send_community_attribute": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Send Community attribute to this neighbor").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_nexthop_self": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Use itself as next hop for this neighbor").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_disable_connection_verification": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Disable Connection Verification").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_tcp_mtu_path_discovery": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Use TCP path MTU discovery.").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_max_hop_count": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Maximum number of hops to reach the neighbor").AddIntegerRangeDescription(1, 255).AddDefaultValueDescription("1").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1, 255), + }, + Default: int64default.StaticInt64(1), + }, + "neighbor_tcp_transport_mode": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("True set it to active, False to passive.").AddDefaultValueDescription("false").String, + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "neighbor_weight": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Weight of the neighbor").AddIntegerRangeDescription(0, 65535).AddDefaultValueDescription("0").String, + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(0, 65535), + }, + Default: int64default.StaticInt64(0), + }, + "neighbor_version": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Set BPG version: 0 - default, 4 - IPv4").AddStringEnumDescription("0", "4").AddDefaultValueDescription("0").String, + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOf("0", "4"), + }, + Default: stringdefault.StaticString("0"), + }, + "neighbor_customized_local_as_number": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Customize the AS number for the routes received from neighbor").String, + Optional: true, + }, + "neighbor_customized_no_prepend": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Do not prepend local AS number to routes received from neighbor").String, + Optional: true, + }, + "neighbor_customized_replace_as": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Replace real AS number with local AS number in routes received from neighbor").String, + Optional: true, + }, + "neighbor_customized_accept_both_as": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Accept either real AS number or local AS number in routes experienced from neighbor").String, + Optional: true, + }, + }, + }, + }, + "ipv4_aggregate_addresses": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "generate_as": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Generate AS set path information").String, + Optional: true, + }, + "filter": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filter all routes from updates (summary only)").String, + Optional: true, + }, + "network_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Network ID").String, + Optional: true, + }, + "advertise_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Advertise Map ID").String, + Optional: true, + }, + "attribute_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Attribute Map ID").String, + Optional: true, + }, + "suppress_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Suppress Map ID").String, + Optional: true, + }, + }, + }, + }, + "ipv4_filterings": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "access_list_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Standard Access List ID").String, + Optional: true, + }, + "network_direction": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Filtering directrion").AddStringEnumDescription("incomingroutefilter", "outgoingroutefilter").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("incomingroutefilter", "outgoingroutefilter"), + }, + }, + "protocol": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Protocol").String, + Optional: true, + }, + "prorocol_process": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Process ID").String, + Optional: true, + }, + }, + }, + }, + "ipv4_networks": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "network_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Network object ID").String, + Optional: true, + }, + "route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Route Map ID").String, + Optional: true, + }, + }, + }, + }, + "ipv4_redistributions": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "source_protocol": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Protocol to redistribute").AddStringEnumDescription("RedistributeConnected", "RedistributeStatic", "RedistributeOSPF", "RedistributeEIGRP").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("RedistributeConnected", "RedistributeStatic", "RedistributeOSPF", "RedistributeEIGRP"), + }, + }, + "route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Route Map ID").String, + Optional: true, + }, + "metric": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Metric value").AddIntegerRangeDescription(0, 4294967295).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 4294967295), + }, + }, + "process_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("process ID").String, + Optional: true, + }, + "match_external1": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Match OSPF External 1 metrics").String, + Optional: true, + }, + "match_external2": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Match OSPF External 2 metrics").String, + Optional: true, + }, + "match_internal": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Match OSPF Internal metrics").String, + Optional: true, + }, + "match_nssa_external1": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Match OSPF NSSA External 1 metrics").String, + Optional: true, + }, + "match_nssa_external2": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Match OSPF NSSA External 2 metrics").String, + Optional: true, + }, + }, + }, + }, + "ipv4_route_injections": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "inject_route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Inject Route Map ID").String, + Optional: true, + }, + "exist_route_map_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Exist Route Map ID").String, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func (r *DeviceBGPResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *DeviceBGPResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceBGP + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, DeviceBGP{}) + res, err := r.client.Post(plan.getPath(), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *DeviceBGPResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceBGP + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *DeviceBGPResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceBGP + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +// Section below is generated&owned by "gen/generator.go". //template:begin delete + +func (r *DeviceBGPResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceBGP + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...) + 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.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// End of section. //template:end delete + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *DeviceBGPResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + idParts := strings.Split(req.ID, ",") + + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), + ) + return + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("device_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_device_bgp_general_settings.go b/internal/provider/resource_fmc_device_bgp_general_settings.go new file mode 100644 index 00000000..c5516b13 --- /dev/null +++ b/internal/provider/resource_fmc_device_bgp_general_settings.go @@ -0,0 +1,424 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "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-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &DeviceBGPGeneralSettingsResource{} + _ resource.ResourceWithImportState = &DeviceBGPGeneralSettingsResource{} +) + +func NewDeviceBGPGeneralSettingsResource() resource.Resource { + return &DeviceBGPGeneralSettingsResource{} +} + +type DeviceBGPGeneralSettingsResource struct { + client *fmc.Client +} + +func (r *DeviceBGPGeneralSettingsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_bgp_general_settings" +} + +func (r *DeviceBGPGeneralSettingsResource) 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 Device BGP General Settings.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("UUID of the parent device (fmc_device.example.id).").String, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Object name; Always set to 'AsaBGPGeneralTable'").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "as_number": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Autonomous System (AS) number in asplain or asdot format").String, + Required: true, + }, + "router_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("String value for the routerID. Possible values can be 'AUTOMATIC' or valid ipv4 address").String, + Optional: true, + }, + "scanning_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Scanning interval of BGP routers for next hop validation in Seconds.").AddIntegerRangeDescription(5, 60).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(5, 60), + }, + }, + "as_number_in_path_attribute": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Range to discard routes that have as-path segments that exceed a specified value.").AddIntegerRangeDescription(1, 254).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 254), + }, + }, + "log_neighbor_changes": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Enable logging of BGP neighbor status changes.").String, + Optional: true, + }, + "tcp_path_mtu_discovery": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Use TCP path MTU discovery.").String, + Optional: true, + }, + "reset_session_upon_failover": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Reset session upon failover").String, + Optional: true, + }, + "enforce_first_peer_as": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Discard updates received from an external BGP (eBGP) peers that do not list their autonomous system (AS) number.").String, + Optional: true, + }, + "use_dot_notation": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Change format of BGP 4-byte autonomous system numbers from asplain (decimal values) to dot notation.").String, + Optional: true, + }, + "aggregate_timer": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Interval at which BGP routes will be aggregated or to disable timer-based router aggregation (in seconds).").AddIntegerRangeDescription(6, 60).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(6, 60), + }, + }, + "default_local_preference": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Default local preference").AddIntegerRangeDescription(0, 4294967295).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 4294967295), + }, + }, + "compare_med_from_different_neighbors": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Allow comparing MED from different neighbors").String, + Optional: true, + }, + "compare_router_id_in_path": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Compare Router ID for identical EBGP paths").String, + Optional: true, + }, + "pick_best_med": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Pick the best-MED path among paths advertised by neighbor AS").String, + Optional: true, + }, + "missing_med_as_best": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Treat missing MED as the best preferred path").String, + Optional: true, + }, + "keepalive_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Keepalive interval in seconds").AddIntegerRangeDescription(0, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 65535), + }, + }, + "hold_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Hold time in seconds").AddIntegerRangeDescription(0, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 65535), + }, + }, + "min_hold_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Minimum hold time (0 or 3-65535 seconds)").AddIntegerRangeDescription(0, 65535).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 65535), + }, + }, + "next_hop_address_tracking": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Enable next hop address tracking").String, + Optional: true, + }, + "next_hop_delay_interval": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Next hop delay interval in seconds").AddIntegerRangeDescription(0, 100).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(0, 100), + }, + }, + "graceful_restart": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Enable graceful restart").String, + Optional: true, + }, + "graceful_restart_restart_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Graceful Restart Time in seconds").AddIntegerRangeDescription(1, 3600).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 3600), + }, + }, + "graceful_restart_stale_path_time": schema.Int64Attribute{ + MarkdownDescription: helpers.NewAttributeDescription("Stalepath Time in seconds").AddIntegerRangeDescription(1, 3600).String, + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 3600), + }, + }, + }, + } +} + +func (r *DeviceBGPGeneralSettingsResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *DeviceBGPGeneralSettingsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceBGPGeneralSettings + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, DeviceBGPGeneralSettings{}) + res, err := r.client.Post(plan.getPath(), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *DeviceBGPGeneralSettingsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceBGPGeneralSettings + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *DeviceBGPGeneralSettingsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceBGPGeneralSettings + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +// Section below is generated&owned by "gen/generator.go". //template:begin delete + +func (r *DeviceBGPGeneralSettingsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceBGPGeneralSettings + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + res, err := r.client.Delete(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), reqMods...) + 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.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// End of section. //template:end delete + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *DeviceBGPGeneralSettingsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + idParts := strings.Split(req.ID, ",") + + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), + ) + return + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("device_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_device_bgp_general_settings_test.go b/internal/provider/resource_fmc_device_bgp_general_settings_test.go new file mode 100644 index 00000000..65d284f4 --- /dev/null +++ b/internal/provider/resource_fmc_device_bgp_general_settings_test.go @@ -0,0 +1,127 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcDeviceBGPGeneralSettings(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bgp_general_settings.test", "name")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "as_number", "65535")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "router_id", "AUTOMATIC")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "scanning_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "as_number_in_path_attribute", "50")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "log_neighbor_changes", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "tcp_path_mtu_discovery", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "reset_session_upon_failover", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "enforce_first_peer_as", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "use_dot_notation", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "aggregate_timer", "30")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "default_local_preference", "100")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "compare_med_from_different_neighbors", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "compare_router_id_in_path", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "pick_best_med", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "missing_med_as_best", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "keepalive_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "hold_time", "180")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "min_hold_time", "0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp_general_settings.test", "next_hop_delay_interval", "5")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBGPGeneralSettingsPrerequisitesConfig + testAccFmcDeviceBGPGeneralSettingsConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBGPGeneralSettingsPrerequisitesConfig + testAccFmcDeviceBGPGeneralSettingsConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccFmcDeviceBGPGeneralSettingsPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcDeviceBGPGeneralSettingsConfig_minimum() string { + config := `resource "fmc_device_bgp_general_settings" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` as_number = "65535"` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcDeviceBGPGeneralSettingsConfig_all() string { + config := `resource "fmc_device_bgp_general_settings" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` as_number = "65535"` + "\n" + config += ` router_id = "AUTOMATIC"` + "\n" + config += ` scanning_interval = 60` + "\n" + config += ` as_number_in_path_attribute = 50` + "\n" + config += ` log_neighbor_changes = false` + "\n" + config += ` tcp_path_mtu_discovery = true` + "\n" + config += ` reset_session_upon_failover = true` + "\n" + config += ` enforce_first_peer_as = true` + "\n" + config += ` use_dot_notation = false` + "\n" + config += ` aggregate_timer = 30` + "\n" + config += ` default_local_preference = 100` + "\n" + config += ` compare_med_from_different_neighbors = true` + "\n" + config += ` compare_router_id_in_path = true` + "\n" + config += ` pick_best_med = true` + "\n" + config += ` missing_med_as_best = false` + "\n" + config += ` keepalive_interval = 60` + "\n" + config += ` hold_time = 180` + "\n" + config += ` min_hold_time = 0` + "\n" + config += ` next_hop_delay_interval = 5` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_device_bgp_test.go b/internal/provider/resource_fmc_device_bgp_test.go new file mode 100644 index 00000000..006fe904 --- /dev/null +++ b/internal/provider/resource_fmc_device_bgp_test.go @@ -0,0 +1,164 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcDeviceBGP(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bgp.test", "name")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bgp.test", "type")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bgp.test", "as_number")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_bgp.test", "ipv4_address_family_type")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_default_information_orginate", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_auto_aummary", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_bgp_supress_inactive", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_synchronization", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_bgp_redistribute_internal", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_external_distance", "20")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_internal_distance", "200")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_local_distance", "200")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_forward_packets_over_multipath_ibgp", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_forward_packets_over_multipath_ebgp", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_address", "10.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_remote_as", "65534")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_bfd", "SINGLE_HOP")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.enable_address_family", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_shutdown", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_description", "My BGP Peer")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_max_prefix", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_warning_only", "true")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_threshold_value", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_filter_restart_interval", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_routes_advertisement_interval", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_routes_remove_private_as", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_keepalive_interval", "60")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_hold_time", "180")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_min_hold_time", "3")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_send_community_attribute", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_nexthop_self", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_disable_connection_verification", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_tcp_mtu_path_discovery", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_max_hop_count", "1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_tcp_transport_mode", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_weight", "0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_bgp.test", "ipv4_neighbors.0.neighbor_version", "0")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBGPPrerequisitesConfig + testAccFmcDeviceBGPConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceBGPPrerequisitesConfig + testAccFmcDeviceBGPConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccFmcDeviceBGPPrerequisitesConfig = ` +variable "device_id" { default = null } // tests will set $TF_VAR_device_id + +resource "fmc_device_bgp_general_settings" "test" { + device_id = var.device_id + as_number = "6353" +} +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcDeviceBGPConfig_minimum() string { + config := `resource "fmc_device_bgp" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcDeviceBGPConfig_all() string { + config := `resource "fmc_device_bgp" "test" {` + "\n" + config += ` device_id = var.device_id` + "\n" + config += ` ipv4_default_information_orginate = false` + "\n" + config += ` ipv4_auto_aummary = false` + "\n" + config += ` ipv4_bgp_supress_inactive = false` + "\n" + config += ` ipv4_synchronization = false` + "\n" + config += ` ipv4_bgp_redistribute_internal = false` + "\n" + config += ` ipv4_external_distance = 20` + "\n" + config += ` ipv4_internal_distance = 200` + "\n" + config += ` ipv4_local_distance = 200` + "\n" + config += ` ipv4_forward_packets_over_multipath_ibgp = 1` + "\n" + config += ` ipv4_forward_packets_over_multipath_ebgp = 1` + "\n" + config += ` ipv4_neighbors = [{` + "\n" + config += ` neighbor_address = "10.1.1.1"` + "\n" + config += ` neighbor_remote_as = "65534"` + "\n" + config += ` neighbor_bfd = "SINGLE_HOP"` + "\n" + config += ` enable_address_family = true` + "\n" + config += ` neighbor_shutdown = false` + "\n" + config += ` neighbor_description = "My BGP Peer"` + "\n" + config += ` neighbor_filter_max_prefix = 1` + "\n" + config += ` neighbor_filter_warning_only = true` + "\n" + config += ` neighbor_filter_threshold_value = 1` + "\n" + config += ` neighbor_filter_restart_interval = 1` + "\n" + config += ` neighbor_routes_advertisement_interval = 1` + "\n" + config += ` neighbor_routes_remove_private_as = false` + "\n" + config += ` neighbor_keepalive_interval = 60` + "\n" + config += ` neighbor_hold_time = 180` + "\n" + config += ` neighbor_min_hold_time = 3` + "\n" + config += ` neighbor_send_community_attribute = false` + "\n" + config += ` neighbor_nexthop_self = false` + "\n" + config += ` neighbor_disable_connection_verification = false` + "\n" + config += ` neighbor_tcp_mtu_path_discovery = false` + "\n" + config += ` neighbor_max_hop_count = 1` + "\n" + config += ` neighbor_tcp_transport_mode = false` + "\n" + config += ` neighbor_weight = 0` + "\n" + config += ` neighbor_version = "0"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_device_ha_pair_monitoring.go b/internal/provider/resource_fmc_device_ha_pair_monitoring.go new file mode 100644 index 00000000..bcc22d99 --- /dev/null +++ b/internal/provider/resource_fmc_device_ha_pair_monitoring.go @@ -0,0 +1,373 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "context" + "fmt" + "net/url" + "strings" + + "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/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netascode/go-fmc" + "github.com/netascode/terraform-provider-fmc/internal/provider/helpers" + "github.com/tidwall/gjson" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin model + +// Ensure provider defined types fully satisfy framework interfaces +var ( + _ resource.Resource = &DeviceHAPairMonitoringResource{} + _ resource.ResourceWithImportState = &DeviceHAPairMonitoringResource{} +) + +func NewDeviceHAPairMonitoringResource() resource.Resource { + return &DeviceHAPairMonitoringResource{} +} + +type DeviceHAPairMonitoringResource struct { + client *fmc.Client +} + +func (r *DeviceHAPairMonitoringResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pair_monitoring" +} + +func (r *DeviceHAPairMonitoringResource) 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 Device HA Pair Monitoring.").String, + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + MarkdownDescription: "The id of the object", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain": schema.StringAttribute{ + MarkdownDescription: "The name of the FMC domain", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("UUID of the parent HA device (fmc_device.example.id).").String, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of the resource.").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "logical_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Logical Name of the monitored interface.").String, + Required: true, + }, + "monitor_interface": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Monitor this interface for failures.").String, + Required: true, + }, + "ipv4_active_address": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Active IPv4 address from the interface.").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ipv4_standby_address": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Standby IPv4 address. It has to be in the same subnet as primaty IP configured on this interface.").String, + Optional: true, + }, + "ipv4_netmask": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("IPv4 Network Mask assigned on the interface.").String, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ipv6_addresses": schema.ListNestedAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "active_address": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Active IPv6 address with prefix. Address has to be configured on the interface.").String, + Optional: true, + }, + "standby_address": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Standby IPv6 address. Address has to be from the same subnet as active IPv6 address.").String, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func (r *DeviceHAPairMonitoringResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*FmcProviderData).Client +} + +// End of section. //template:end model + +// Section below is generated&owned by "gen/generator.go". //template:begin create + +func (r *DeviceHAPairMonitoringResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceHAPairMonitoring + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: considering object logical_name %s", plan.Id, plan.LogicalName)) + if plan.Id.ValueString() == "" && plan.LogicalName.ValueString() != "" { + offset := 0 + limit := 1000 + for page := 1; ; page++ { + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) + res, err := r.client.Get(plan.getPath()+queryString, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) + return + } + if value := res.Get("items"); len(value.Array()) > 0 { + value.ForEach(func(k, v gjson.Result) bool { + if plan.LogicalName.ValueString() == v.Get("name").String() { + plan.Id = types.StringValue(v.Get("id").String()) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with logical_name '%s', id: %s", plan.Id, plan.LogicalName.ValueString(), plan.Id)) + return false + } + return true + }) + } + if plan.Id.ValueString() != "" || !res.Get("paging.next.0").Exists() { + break + } + offset += limit + } + + if plan.Id.ValueString() == "" { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with logical_name: %s", plan.LogicalName.ValueString())) + return + } + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) + + // Create object + body := plan.toBody(ctx, DeviceHAPairMonitoring{}) + res, err := r.client.Put(plan.getPath()+"/"+url.PathEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String())) + return + } + plan.Id = types.StringValue(res.Get("id").String()) + plan.fromBodyUnknowns(ctx, res) + + tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end create + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *DeviceHAPairMonitoringResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceHAPairMonitoring + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) + + urlPath := state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()) + res, err := r.client.Get(urlPath, reqMods...) + + if err != nil && strings.Contains(err.Error(), "StatusCode 404") { + 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 + } + + imp, diags := helpers.IsFlagImporting(ctx, req) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // After `terraform import` we switch to a full read. + if imp { + state.fromBody(ctx, res) + } else { + state.fromBodyPartial(ctx, res) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString())) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end read + +// Section below is generated&owned by "gen/generator.go". //template:begin update + +func (r *DeviceHAPairMonitoringResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceHAPairMonitoring + + // Read plan + diags := req.Plan.Get(ctx, &plan) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Read state + diags = req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + + body := plan.toBody(ctx, state) + res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) +} + +// End of section. //template:end update + +func (r *DeviceHAPairMonitoringResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceHAPairMonitoring + + // Read state + diags := req.State.Get(ctx, &state) + if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() { + return + } + + // Set request domain if provided + reqMods := [](func(*fmc.Req)){} + if !state.Domain.IsNull() && state.Domain.ValueString() != "" { + reqMods = append(reqMods, fmc.DomainName(state.Domain.ValueString())) + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) + body := state.toBodyPutDelete(ctx, DeviceHAPairMonitoring{}) + res, err := r.client.Put(state.getPath()+"/"+url.QueryEscape(state.Id.ValueString()), body, reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to remove object configuration (PUT), got error: %s, %s", err, res.String())) + return + } + + tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString())) + + resp.State.RemoveResource(ctx) +} + +// Section below is generated&owned by "gen/generator.go". //template:begin import + +func (r *DeviceHAPairMonitoringResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + idParts := strings.Split(req.ID, ",") + + if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), + ) + return + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("device_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) + + helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics) +} + +// End of section. //template:end import + +// Section below is generated&owned by "gen/generator.go". //template:begin createSubresources + +// End of section. //template:end createSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin deleteSubresources + +// End of section. //template:end deleteSubresources + +// Section below is generated&owned by "gen/generator.go". //template:begin updateSubresources + +// End of section. //template:end updateSubresources diff --git a/internal/provider/resource_fmc_device_ha_pair_monitoring_test.go b/internal/provider/resource_fmc_device_ha_pair_monitoring_test.go new file mode 100644 index 00000000..4f4f230f --- /dev/null +++ b/internal/provider/resource_fmc_device_ha_pair_monitoring_test.go @@ -0,0 +1,104 @@ +// 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 + +package provider + +// Section below is generated&owned by "gen/generator.go". //template:begin imports +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +// End of section. //template:end imports + +// Section below is generated&owned by "gen/generator.go". //template:begin testAcc + +func TestAccFmcDeviceHAPairMonitoring(t *testing.T) { + if os.Getenv("TF_VAR_device_ha_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_ha_id") + } + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_ha_pair_monitoring.test", "type")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair_monitoring.test", "logical_name", "outside")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair_monitoring.test", "monitor_interface", "true")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_ha_pair_monitoring.test", "ipv4_active_address")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair_monitoring.test", "ipv4_standby_address", "10.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttrSet("fmc_device_ha_pair_monitoring.test", "ipv4_netmask")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair_monitoring.test", "ipv6_addresses.0.active_address", "2006::1/30")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair_monitoring.test", "ipv6_addresses.0.standby_address", "2006::2")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceHAPairMonitoringPrerequisitesConfig + testAccFmcDeviceHAPairMonitoringConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceHAPairMonitoringPrerequisitesConfig + testAccFmcDeviceHAPairMonitoringConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + ErrorCheck: func(err error) error { return testAccErrorCheck(t, err) }, + Steps: steps, + }) +} + +// End of section. //template:end testAcc + +// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccFmcDeviceHAPairMonitoringPrerequisitesConfig = ` +variable "device_ha_id" { default = null } // tests will set $TF_VAR_device_ha_id +` + +// End of section. //template:end testPrerequisites + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal + +func testAccFmcDeviceHAPairMonitoringConfig_minimum() string { + config := `resource "fmc_device_ha_pair_monitoring" "test" {` + "\n" + config += ` device_id = var.device_ha_id` + "\n" + config += ` logical_name = "outside"` + "\n" + config += ` monitor_interface = true` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigMinimal + +// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll + +func testAccFmcDeviceHAPairMonitoringConfig_all() string { + config := `resource "fmc_device_ha_pair_monitoring" "test" {` + "\n" + config += ` device_id = var.device_ha_id` + "\n" + config += ` logical_name = "outside"` + "\n" + config += ` monitor_interface = true` + "\n" + config += ` ipv4_standby_address = "10.1.1.2"` + "\n" + config += ` ipv6_addresses = [{` + "\n" + config += ` active_address = "2006::1/30"` + "\n" + config += ` standby_address = "2006::2"` + "\n" + config += ` }]` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll diff --git a/internal/provider/resource_fmc_device_physical_interface.go b/internal/provider/resource_fmc_device_physical_interface.go index 0aa6e5e1..84da5122 100644 --- a/internal/provider/resource_fmc_device_physical_interface.go +++ b/internal/provider/resource_fmc_device_physical_interface.go @@ -498,13 +498,13 @@ func (r *DevicePhysicalInterfaceResource) Create(ctx context.Context, req resour if !plan.Domain.IsNull() && plan.Domain.ValueString() != "" { reqMods = append(reqMods, fmc.DomainName(plan.Domain.ValueString())) } - tflog.Debug(ctx, fmt.Sprintf("%s: considering object name %s", plan.Id, plan.Name)) + tflog.Debug(ctx, fmt.Sprintf("%s: considering object name %s", plan.Id, plan.Name)) if plan.Id.ValueString() == "" && plan.Name.ValueString() != "" { offset := 0 limit := 1000 for page := 1; ; page++ { - queryString := fmt.Sprintf("?limit=%d&offset=%d", limit, offset) + queryString := fmt.Sprintf("?limit=%d&offset=%d&expanded=true", limit, offset) res, err := r.client.Get(plan.getPath()+queryString, reqMods...) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) diff --git a/internal/provider/resource_fmc_device_vtep_policy.go b/internal/provider/resource_fmc_device_vtep_policy.go index 1a91249e..32ee0fe0 100644 --- a/internal/provider/resource_fmc_device_vtep_policy.go +++ b/internal/provider/resource_fmc_device_vtep_policy.go @@ -129,9 +129,6 @@ func (r *DeviceVTEPPolicyResource) Schema(ctx context.Context, req resource.Sche stringvalidator.OneOf("VXLAN", "GENEVE"), }, Default: stringdefault.StaticString("VXLAN"), - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, }, "neighbor_discovery": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("How to discover addresses of the neighbor VTEPs for the VTEP-to-VTEP communication. For STATIC_PEER_IP and DEFAULT_MULTICAST_GROUP you must set `neighbor_address_literal` to a single IP address. For STATIC_PEER_GROUP you must however set `neighbor_address_id` to a UUID of a network group and such network group can contain only IPv4 Hosts and IPv4 Ranges (but not Networks, etc.).").AddStringEnumDescription("NONE", "STATIC_PEER_IP", "STATIC_PEER_GROUP", "DEFAULT_MULTICAST_GROUP").String, diff --git a/internal/provider/resource_fmc_network.go b/internal/provider/resource_fmc_network.go index c96138f1..eac41b2d 100644 --- a/internal/provider/resource_fmc_network.go +++ b/internal/provider/resource_fmc_network.go @@ -28,7 +28,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -83,12 +82,10 @@ func (r *NetworkResource) Schema(ctx context.Context, req resource.SchemaRequest Required: true, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'Network'.").AddDefaultValueDescription("Network").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'Network'.").String, Computed: true, - Default: stringdefault.StaticString("Network"), PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, "description": schema.StringAttribute{ diff --git a/internal/provider/resource_fmc_networks.go b/internal/provider/resource_fmc_networks.go index 1597369d..7e9325d9 100644 --- a/internal/provider/resource_fmc_networks.go +++ b/internal/provider/resource_fmc_networks.go @@ -32,7 +32,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -108,10 +107,11 @@ func (r *NetworksResource) Schema(ctx context.Context, req resource.SchemaReques Required: true, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'Network'.").AddDefaultValueDescription("Network").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'Network'.").String, Computed: true, - Default: stringdefault.StaticString("Network"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, }, diff --git a/internal/provider/resource_fmc_port_group.go b/internal/provider/resource_fmc_port_group.go index e3f77c72..c908f395 100644 --- a/internal/provider/resource_fmc_port_group.go +++ b/internal/provider/resource_fmc_port_group.go @@ -29,7 +29,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -85,12 +84,10 @@ func (r *PortGroupResource) Schema(ctx context.Context, req resource.SchemaReque Required: true, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'PortObjectGroup'.").AddDefaultValueDescription("PortObjectGroup").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'PortObjectGroup'.").String, Computed: true, - Default: stringdefault.StaticString("PortObjectGroup"), PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, "description": schema.StringAttribute{ diff --git a/internal/provider/resource_fmc_port_groups.go b/internal/provider/resource_fmc_port_groups.go index f0d5e832..ba2dc48c 100644 --- a/internal/provider/resource_fmc_port_groups.go +++ b/internal/provider/resource_fmc_port_groups.go @@ -33,7 +33,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -98,12 +97,10 @@ func (r *PortGroupsResource) Schema(ctx context.Context, req resource.SchemaRequ }, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'PortObjectGroup'.").AddDefaultValueDescription("PortObjectGroup").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'PortObjectGroup'.").String, Computed: true, - Default: stringdefault.StaticString("PortObjectGroup"), PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, "description": schema.StringAttribute{ diff --git a/internal/provider/resource_fmc_security_zone.go b/internal/provider/resource_fmc_security_zone.go index 494b20c7..8a4f1b4a 100644 --- a/internal/provider/resource_fmc_security_zone.go +++ b/internal/provider/resource_fmc_security_zone.go @@ -29,7 +29,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -84,21 +83,19 @@ func (r *SecurityZoneResource) Schema(ctx context.Context, req resource.SchemaRe MarkdownDescription: helpers.NewAttributeDescription("User-provided resource name.").String, Required: true, }, - "interface_mode": schema.StringAttribute{ + "interface_type": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces.").AddStringEnumDescription("PASSIVE", "INLINE", "SWITCHED", "ROUTED", "ASA").String, Required: true, Validators: []validator.String{ stringvalidator.OneOf("PASSIVE", "INLINE", "SWITCHED", "ROUTED", "ASA"), }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'SecurityZone'.").AddDefaultValueDescription("SecurityZone").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'SecurityZone'.").String, Computed: true, - Default: stringdefault.StaticString("SecurityZone"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } diff --git a/internal/provider/resource_fmc_security_zone_test.go b/internal/provider/resource_fmc_security_zone_test.go index b178caeb..c535d642 100644 --- a/internal/provider/resource_fmc_security_zone_test.go +++ b/internal/provider/resource_fmc_security_zone_test.go @@ -32,7 +32,7 @@ import ( func TestAccFmcSecurityZone(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("fmc_security_zone.test", "name", "security_zone_1")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_security_zone.test", "interface_mode", "ROUTED")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_security_zone.test", "interface_type", "ROUTED")) var steps []resource.TestStep if os.Getenv("SKIP_MINIMUM_TEST") == "" { @@ -67,7 +67,7 @@ func TestAccFmcSecurityZone(t *testing.T) { func testAccFmcSecurityZoneConfig_minimum() string { config := `resource "fmc_security_zone" "test" {` + "\n" config += ` name = "security_zone_1"` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += `}` + "\n" return config } @@ -79,7 +79,7 @@ func testAccFmcSecurityZoneConfig_minimum() string { func testAccFmcSecurityZoneConfig_all() string { config := `resource "fmc_security_zone" "test" {` + "\n" config += ` name = "security_zone_1"` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += `}` + "\n" return config } diff --git a/internal/provider/resource_fmc_security_zones.go b/internal/provider/resource_fmc_security_zones.go index 162ef4fe..7e0730e4 100644 --- a/internal/provider/resource_fmc_security_zones.go +++ b/internal/provider/resource_fmc_security_zones.go @@ -33,7 +33,6 @@ import ( "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/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -97,21 +96,19 @@ func (r *SecurityZonesResource) Schema(ctx context.Context, req resource.SchemaR stringplanmodifier.UseStateForUnknown(), }, }, - "interface_mode": schema.StringAttribute{ + "interface_type": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("The mode of the associated interfaces, with the exception of mode ROUTED that corresponds to mode NONE of associated interfaces.").AddStringEnumDescription("PASSIVE", "INLINE", "SWITCHED", "ROUTED", "ASA").String, Required: true, Validators: []validator.String{ stringvalidator.OneOf("PASSIVE", "INLINE", "SWITCHED", "ROUTED", "ASA"), }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, }, "type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'SecurityZone'.").AddDefaultValueDescription("SecurityZone").String, - Optional: true, + MarkdownDescription: helpers.NewAttributeDescription("Type of the object; this value is always 'SecurityZone'.").String, Computed: true, - Default: stringdefault.StaticString("SecurityZone"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, }, diff --git a/internal/provider/resource_fmc_security_zones_test.go b/internal/provider/resource_fmc_security_zones_test.go index 5cd02e4d..7ae4611d 100644 --- a/internal/provider/resource_fmc_security_zones_test.go +++ b/internal/provider/resource_fmc_security_zones_test.go @@ -32,7 +32,7 @@ import ( func TestAccFmcSecurityZones(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttrSet("fmc_security_zones.test", "items.security_zone_1.id")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_security_zones.test", "items.security_zone_1.interface_mode", "ROUTED")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_security_zones.test", "items.security_zone_1.interface_type", "ROUTED")) var steps []resource.TestStep if os.Getenv("SKIP_MINIMUM_TEST") == "" { @@ -63,7 +63,7 @@ func TestAccFmcSecurityZones(t *testing.T) { func testAccFmcSecurityZonesConfig_minimum() string { config := `resource "fmc_security_zones" "test" {` + "\n" config += ` items = { "security_zone_1" = {` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += ` }}` + "\n" config += `}` + "\n" return config @@ -76,7 +76,7 @@ func testAccFmcSecurityZonesConfig_minimum() string { func testAccFmcSecurityZonesConfig_all() string { config := `resource "fmc_security_zones" "test" {` + "\n" config += ` items = { "security_zone_1" = {` + "\n" - config += ` interface_mode = "ROUTED"` + "\n" + config += ` interface_type = "ROUTED"` + "\n" config += ` }}` + "\n" config += `}` + "\n" return config