From 82e9d2220fb7831fa4173cba56e97c81a94ae7e1 Mon Sep 17 00:00:00 2001 From: kadadhic Date: Wed, 4 Dec 2024 18:40:18 +0530 Subject: [PATCH 1/6] adding support for HA --- .gitignore | 3 +- docs/data-sources/device_ha_pairs.md | 55 +++ docs/resources/device_ha_pairs.md | 91 ++++ .../fmc_device_ha_pairs/data-source.tf | 3 + .../resources/fmc_device_ha_pairs/import.sh | 1 + .../resources/fmc_device_ha_pairs/resource.tf | 27 ++ gen/definitions/high_availability.yaml | 145 ++++++ .../data_source_fmc_device_ha_pairs.go | 263 +++++++++++ .../data_source_fmc_device_ha_pairs_test.go | 155 ++++++ .../provider/model_fmc_device_ha_pairs.go | 444 ++++++++++++++++++ internal/provider/provider.go | 2 + .../provider/resource_fmc_device_ha_pairs.go | 418 +++++++++++++++++ .../resource_fmc_device_ha_pairs_test.go | 138 ++++++ 13 files changed, 1744 insertions(+), 1 deletion(-) create mode 100644 docs/data-sources/device_ha_pairs.md create mode 100644 docs/resources/device_ha_pairs.md create mode 100644 examples/data-sources/fmc_device_ha_pairs/data-source.tf create mode 100644 examples/resources/fmc_device_ha_pairs/import.sh create mode 100644 examples/resources/fmc_device_ha_pairs/resource.tf create mode 100644 gen/definitions/high_availability.yaml create mode 100644 internal/provider/data_source_fmc_device_ha_pairs.go create mode 100644 internal/provider/data_source_fmc_device_ha_pairs_test.go create mode 100644 internal/provider/model_fmc_device_ha_pairs.go create mode 100644 internal/provider/resource_fmc_device_ha_pairs.go create mode 100644 internal/provider/resource_fmc_device_ha_pairs_test.go diff --git a/.gitignore b/.gitignore index fad74c21..7d764a69 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,8 @@ website/node_modules .vscode/settings.json website/vendor - +vendor +running.sh # Test exclusions !command/test-fixtures/**/*.tfstate !command/test-fixtures/**/.terraform/ diff --git a/docs/data-sources/device_ha_pairs.md b/docs/data-sources/device_ha_pairs.md new file mode 100644 index 00000000..6befd1da --- /dev/null +++ b/docs/data-sources/device_ha_pairs.md @@ -0,0 +1,55 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_ha_pairs Data Source - terraform-provider-fmc" +subcategory: "Device" +description: |- + This data source can read the Device HA Pairs. +--- + +# fmc_device_ha_pairs (Data Source) + +This data source can read the Device HA Pairs. + +## Example Usage + +```terraform +data "fmc_device_ha_pairs" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} +``` + + +## Schema + +### Optional + +- `domain` (String) The name of the FMC domain +- `id` (String) The id of the object +- `lan_failover_interface_name` (String) Name of physical interface +- `name` (String) The name of the access control policy. +- `stateful_failover_interface_name` (String) Name of physical interface + +### Read-Only + +- `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. +- `enc_key_generation_scheme` (String) +- `force_break` (Boolean) FTD HA Force Break option (PUT Option). +- `is_encryption_enabled` (Boolean) +- `lan_failover_active_ip` (String) +- `lan_failover_interface_id` (String) ID of physical interface. +- `lan_failover_interface_type` (String) Type of physical interface. +- `lan_failover_ipv6_addr` (Boolean) +- `lan_failover_name` (String) +- `lan_failover_standby_ip` (String) +- `lan_failover_subnet_mask` (String) +- `primary_device_id` (String) ID of primary FTD in the HA Pair. +- `secondary_device_id` (String) ID of secondary FTD in the HA Pair. +- `shared_key` (String) +- `stateful_failover_active_ip` (String) +- `stateful_failover_interface_id` (String) ID of physical interface. +- `stateful_failover_interface_type` (String) Type of physical interface. +- `stateful_failover_ipv6_addr` (Boolean) +- `stateful_failover_name` (String) +- `stateful_failover_standby_ip` (String) +- `stateful_failover_subnet_mask` (String) +- `use_same_link_for_failovers` (Boolean) diff --git a/docs/resources/device_ha_pairs.md b/docs/resources/device_ha_pairs.md new file mode 100644 index 00000000..101bf78c --- /dev/null +++ b/docs/resources/device_ha_pairs.md @@ -0,0 +1,91 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "fmc_device_ha_pairs Resource - terraform-provider-fmc" +subcategory: "Device" +description: |- + This resource can manage a Device HA Pairs. +--- + +# fmc_device_ha_pairs (Resource) + +This resource can manage a Device HA Pairs. + +## Example Usage + +```terraform +resource "fmc_device_ha_pairs" "example" { + name = "FTD_HA" + primary_device_id = "" + secondary_device_id = "" + 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 = "" + lan_failover_interface_type = "PhysicalInterface" + stateful_failover_standby_ip = "1.1.1.2" + stateful_failover_active_ip = "1.1.1.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 = "" + stateful_failover_interface_type = "PhysicalInterface" + action = "SWITCH" + force_break = false +} +``` + + +## Schema + +### Required + +- `lan_failover_active_ip` (String) +- `lan_failover_interface_id` (String) ID of physical interface. +- `lan_failover_name` (String) +- `lan_failover_standby_ip` (String) +- `name` (String) The name of the access control policy. +- `primary_device_id` (String) ID of primary FTD in the HA Pair. +- `secondary_device_id` (String) ID of secondary FTD in the HA Pair. +- `use_same_link_for_failovers` (Boolean) + +### Optional + +- `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. + - Choices: `SWITCH`, `HABREAK` +- `domain` (String) The name of the FMC domain +- `enc_key_generation_scheme` (String) - Choices: `AUTO`, `CUSTOM` +- `force_break` (Boolean) FTD HA Force Break option (PUT Option). +- `is_encryption_enabled` (Boolean) +- `lan_failover_interface_name` (String) Name of physical interface +- `lan_failover_interface_type` (String) Type of physical interface. +- `lan_failover_ipv6_addr` (Boolean) +- `lan_failover_subnet_mask` (String) +- `shared_key` (String) +- `stateful_failover_active_ip` (String) +- `stateful_failover_interface_id` (String) ID of physical interface. +- `stateful_failover_interface_name` (String) Name of physical interface +- `stateful_failover_interface_type` (String) Type of physical interface. +- `stateful_failover_ipv6_addr` (Boolean) +- `stateful_failover_name` (String) +- `stateful_failover_standby_ip` (String) +- `stateful_failover_subnet_mask` (String) + +### Read-Only + +- `id` (String) The id of the object + +## Import + +Import is supported using the following syntax: + +```shell +terraform import fmc_device_ha_pairs.example "" +``` diff --git a/examples/data-sources/fmc_device_ha_pairs/data-source.tf b/examples/data-sources/fmc_device_ha_pairs/data-source.tf new file mode 100644 index 00000000..50f3b111 --- /dev/null +++ b/examples/data-sources/fmc_device_ha_pairs/data-source.tf @@ -0,0 +1,3 @@ +data "fmc_device_ha_pairs" "example" { + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" +} diff --git a/examples/resources/fmc_device_ha_pairs/import.sh b/examples/resources/fmc_device_ha_pairs/import.sh new file mode 100644 index 00000000..ea9a2e67 --- /dev/null +++ b/examples/resources/fmc_device_ha_pairs/import.sh @@ -0,0 +1 @@ +terraform import fmc_device_ha_pairs.example "" diff --git a/examples/resources/fmc_device_ha_pairs/resource.tf b/examples/resources/fmc_device_ha_pairs/resource.tf new file mode 100644 index 00000000..fc4def7f --- /dev/null +++ b/examples/resources/fmc_device_ha_pairs/resource.tf @@ -0,0 +1,27 @@ +resource "fmc_device_ha_pairs" "example" { + name = "FTD_HA" + primary_device_id = "" + secondary_device_id = "" + 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 = "" + lan_failover_interface_type = "PhysicalInterface" + stateful_failover_standby_ip = "1.1.1.2" + stateful_failover_active_ip = "1.1.1.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 = "" + stateful_failover_interface_type = "PhysicalInterface" + action = "SWITCH" + force_break = false +} diff --git a/gen/definitions/high_availability.yaml b/gen/definitions/high_availability.yaml new file mode 100644 index 00000000..fb46dde3 --- /dev/null +++ b/gen/definitions/high_availability.yaml @@ -0,0 +1,145 @@ +--- +name: Device HA Pairs +rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs +data_source_name_query: true +doc_category: Device +attributes: + - model_name: name + type: String + mandatory: true + description: The name of the access control policy. + example: FTD_HA + - model_name: type + type: String + value: DeviceHAPair + - model_name: id + type: String + mandatory: true + tf_name: primary_device_id + data_path: [primary] + description: ID of primary FTD in the HA Pair. + example: + - model_name: id + type: String + mandatory: true + tf_name: secondary_device_id + data_path: [secondary] + description: ID of secondary FTD in the HA Pair. + example: + - model_name: isEncryptionEnabled + type: Bool + data_path: [ftdHABootstrap] + example: false + - model_name: useSameLinkForFailovers + type: Bool + mandatory: true + data_path: [ftdHABootstrap] + example: false + - model_name: sharedKey + type: String + data_path: [ftdHABootstrap] + example: cisco123 + - model_name: encKeyGenerationScheme + type: String + data_path: [ftdHABootstrap] + example: CUSTOM + enum_values: [ AUTO, CUSTOM ] + - model_name: standbyIP + type: String + mandatory: true + tf_name: lan_failover_standby_ip + data_path: [ftdHABootstrap,lanFailover] + example: "1.1.1.2" + - model_name: activeIP + tf_name: lan_failover_active_ip + mandatory: true + type: String + data_path: [ftdHABootstrap,lanFailover] + example: "1.1.1.1" + - model_name: logicalName + type: String + mandatory: true + tf_name: lan_failover_name + data_path: [ftdHABootstrap,lanFailover] + example: LAN-INTERFACE + - model_name: subnetMask + type: String + tf_name: lan_failover_subnet_mask + data_path: [ftdHABootstrap,lanFailover] + example: "255.255.255.0" + - model_name: useIPv6Address + type: Bool + tf_name: lan_failover_ipv6_addr + data_path: [ftdHABootstrap,lanFailover] + example: false + - model_name: name + type: String + tf_name: lan_failover_interface_name + data_path: [ftdHABootstrap,lanFailover,interfaceObject] + description: Name of physical interface + example: GigabitEthernet0/0 + - model_name: id + type: String + mandatory: true + tf_name: lan_failover_interface_id + data_path: [ftdHABootstrap,lanFailover,interfaceObject] + description: ID of physical interface. + example: + - model_name: type + type: String + tf_name: lan_failover_interface_type + data_path: [ftdHABootstrap,lanFailover,interfaceObject] + description: Type of physical interface. + example: PhysicalInterface + - model_name: standbyIP + type: String + tf_name: stateful_failover_standby_ip + data_path: [ftdHABootstrap,statefulFailover] + example: "1.1.1.2" + - model_name: activeIP + tf_name: stateful_failover_active_ip + type: String + data_path: [ftdHABootstrap,statefulFailover] + example: "1.1.1.1" + - model_name: logicalName + type: String + tf_name: stateful_failover_name + data_path: [ftdHABootstrap,statefulFailover] + example: Stateful-INTERFACE + - model_name: subnetMask + type: String + tf_name: stateful_failover_subnet_mask + data_path: [ftdHABootstrap,statefulFailover] + example: "255.255.255.0" + - model_name: useIPv6Address + type: Bool + tf_name: stateful_failover_ipv6_addr + data_path: [ftdHABootstrap,statefulFailover] + example: false + - model_name: name + type: String + tf_name: stateful_failover_interface_name + data_path: [ftdHABootstrap,statefulFailover,interfaceObject] + description: Name of physical interface + example: GigabitEthernet0/0 + - model_name: id + type: String + tf_name: stateful_failover_interface_id + data_path: [ftdHABootstrap,statefulFailover,interfaceObject] + description: ID of physical interface. + example: + - model_name: type + type: String + tf_name: stateful_failover_interface_type + data_path: [ftdHABootstrap,statefulFailover,interfaceObject] + description: Type of physical interface. + example: PhysicalInterface + - model_name: action + type: String + description: FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. + enum_values: [ SWITCH, HABREAK ] + example: SWITCH + - model_name: forceBreak + type: Bool + description: FTD HA Force Break option (PUT Option). + example: false diff --git a/internal/provider/data_source_fmc_device_ha_pairs.go b/internal/provider/data_source_fmc_device_ha_pairs.go new file mode 100644 index 00000000..dc322616 --- /dev/null +++ b/internal/provider/data_source_fmc_device_ha_pairs.go @@ -0,0 +1,263 @@ +// 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 = &DeviceHAPairsDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceHAPairsDataSource{} +) + +func NewDeviceHAPairsDataSource() datasource.DataSource { + return &DeviceHAPairsDataSource{} +} + +type DeviceHAPairsDataSource struct { + client *fmc.Client +} + +func (d *DeviceHAPairsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pairs" +} + +func (d *DeviceHAPairsDataSource) 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 Pairs.", + + 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 access control policy.", + Optional: true, + Computed: true, + }, + "primary_device_id": schema.StringAttribute{ + MarkdownDescription: "ID of primary FTD in the HA Pair.", + Computed: true, + }, + "secondary_device_id": schema.StringAttribute{ + MarkdownDescription: "ID of secondary FTD in the HA Pair.", + Computed: true, + }, + "is_encryption_enabled": schema.BoolAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "use_same_link_for_failovers": schema.BoolAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "shared_key": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "enc_key_generation_scheme": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_standby_ip": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_active_ip": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_name": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_subnet_mask": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_ipv6_addr": schema.BoolAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "lan_failover_interface_name": schema.StringAttribute{ + MarkdownDescription: "Name of physical interface", + Optional: true, + Computed: true, + }, + "lan_failover_interface_id": schema.StringAttribute{ + MarkdownDescription: "ID of physical interface.", + Computed: true, + }, + "lan_failover_interface_type": schema.StringAttribute{ + MarkdownDescription: "Type of physical interface.", + Computed: true, + }, + "stateful_failover_standby_ip": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "stateful_failover_active_ip": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "stateful_failover_name": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "stateful_failover_subnet_mask": schema.StringAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "stateful_failover_ipv6_addr": schema.BoolAttribute{ + MarkdownDescription: "", + Computed: true, + }, + "stateful_failover_interface_name": schema.StringAttribute{ + MarkdownDescription: "Name of physical interface", + Optional: true, + Computed: true, + }, + "stateful_failover_interface_id": schema.StringAttribute{ + MarkdownDescription: "ID of physical interface.", + Computed: true, + }, + "stateful_failover_interface_type": schema.StringAttribute{ + MarkdownDescription: "Type of physical interface.", + Computed: true, + }, + "action": schema.StringAttribute{ + MarkdownDescription: "FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch.", + Computed: true, + }, + "force_break": schema.BoolAttribute{ + MarkdownDescription: "FTD HA Force Break option (PUT Option).", + Computed: true, + }, + }, + } +} +func (d *DeviceHAPairsDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf( + path.MatchRoot("id"), + path.MatchRoot("name"), + ), + } +} + +func (d *DeviceHAPairsDataSource) 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 *DeviceHAPairsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceHAPairs + + // 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", 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_device_ha_pairs_test.go b/internal/provider/data_source_fmc_device_ha_pairs_test.go new file mode 100644 index 00000000..414ba591 --- /dev/null +++ b/internal/provider/data_source_fmc_device_ha_pairs_test.go @@ -0,0 +1,155 @@ +// 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 TestAccDataSourceFmcDeviceHAPairs(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "name", "FTD_HA")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "primary_device_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "secondary_device_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "is_encryption_enabled", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "use_same_link_for_failovers", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "shared_key", "cisco123")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "enc_key_generation_scheme", "CUSTOM")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_name", "LAN-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_name", "Stateful-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "action", "SWITCH")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "force_break", "false")) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFmcDeviceHAPairsConfig(), + Check: resource.ComposeTestCheckFunc(checks...), + }, + { + Config: testAccNamedDataSourceFmcDeviceHAPairsConfig(), + 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 testAccDataSourceFmcDeviceHAPairsConfig() string { + config := `resource "fmc_device_ha_pairs" "test" {` + "\n" + config += ` name = "FTD_HA"` + "\n" + config += ` primary_device_id = ""` + "\n" + config += ` secondary_device_id = ""` + "\n" + config += ` is_encryption_enabled = false` + "\n" + config += ` use_same_link_for_failovers = false` + "\n" + config += ` shared_key = "cisco123"` + "\n" + config += ` enc_key_generation_scheme = "CUSTOM"` + "\n" + config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" + config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" + config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_ipv6_addr = false` + "\n" + config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" + config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` stateful_failover_ipv6_addr = false` + "\n" + config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` action = "SWITCH"` + "\n" + config += ` force_break = false` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_ha_pairs" "test" { + id = fmc_device_ha_pairs.test.id + } + ` + return config +} + +func testAccNamedDataSourceFmcDeviceHAPairsConfig() string { + config := `resource "fmc_device_ha_pairs" "test" {` + "\n" + config += ` name = "FTD_HA"` + "\n" + config += ` primary_device_id = ""` + "\n" + config += ` secondary_device_id = ""` + "\n" + config += ` is_encryption_enabled = false` + "\n" + config += ` use_same_link_for_failovers = false` + "\n" + config += ` shared_key = "cisco123"` + "\n" + config += ` enc_key_generation_scheme = "CUSTOM"` + "\n" + config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" + config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" + config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_ipv6_addr = false` + "\n" + config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" + config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` stateful_failover_ipv6_addr = false` + "\n" + config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` action = "SWITCH"` + "\n" + config += ` force_break = false` + "\n" + config += `}` + "\n" + + config += ` + data "fmc_device_ha_pairs" "test" { + name = fmc_device_ha_pairs.test.name + } + ` + return config +} + +// End of section. //template:end testAccDataSourceConfig diff --git a/internal/provider/model_fmc_device_ha_pairs.go b/internal/provider/model_fmc_device_ha_pairs.go new file mode 100644 index 00000000..d792a3e5 --- /dev/null +++ b/internal/provider/model_fmc_device_ha_pairs.go @@ -0,0 +1,444 @@ +// 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 DeviceHAPairs struct { + Id types.String `tfsdk:"id"` + Domain types.String `tfsdk:"domain"` + Name types.String `tfsdk:"name"` + PrimaryDeviceId types.String `tfsdk:"primary_device_id"` + SecondaryDeviceId types.String `tfsdk:"secondary_device_id"` + IsEncryptionEnabled types.Bool `tfsdk:"is_encryption_enabled"` + UseSameLinkForFailovers types.Bool `tfsdk:"use_same_link_for_failovers"` + SharedKey types.String `tfsdk:"shared_key"` + EncKeyGenerationScheme types.String `tfsdk:"enc_key_generation_scheme"` + LanFailoverStandbyIp types.String `tfsdk:"lan_failover_standby_ip"` + LanFailoverActiveIp types.String `tfsdk:"lan_failover_active_ip"` + LanFailoverName types.String `tfsdk:"lan_failover_name"` + LanFailoverSubnetMask types.String `tfsdk:"lan_failover_subnet_mask"` + LanFailoverIpv6Addr types.Bool `tfsdk:"lan_failover_ipv6_addr"` + LanFailoverInterfaceName types.String `tfsdk:"lan_failover_interface_name"` + LanFailoverInterfaceId types.String `tfsdk:"lan_failover_interface_id"` + LanFailoverInterfaceType types.String `tfsdk:"lan_failover_interface_type"` + StatefulFailoverStandbyIp types.String `tfsdk:"stateful_failover_standby_ip"` + StatefulFailoverActiveIp types.String `tfsdk:"stateful_failover_active_ip"` + StatefulFailoverName types.String `tfsdk:"stateful_failover_name"` + StatefulFailoverSubnetMask types.String `tfsdk:"stateful_failover_subnet_mask"` + StatefulFailoverIpv6Addr types.Bool `tfsdk:"stateful_failover_ipv6_addr"` + StatefulFailoverInterfaceName types.String `tfsdk:"stateful_failover_interface_name"` + StatefulFailoverInterfaceId types.String `tfsdk:"stateful_failover_interface_id"` + StatefulFailoverInterfaceType types.String `tfsdk:"stateful_failover_interface_type"` + Action types.String `tfsdk:"action"` + ForceBreak types.Bool `tfsdk:"force_break"` +} + +// End of section. //template:end types + +// Section below is generated&owned by "gen/generator.go". //template:begin getPath + +func (data DeviceHAPairs) getPath() string { + return "/api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs" +} + +// End of section. //template:end getPath + +// Section below is generated&owned by "gen/generator.go". //template:begin toBody + +func (data DeviceHAPairs) toBody(ctx context.Context, state DeviceHAPairs) 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()) + } + body, _ = sjson.Set(body, "type", "DeviceHAPair") + if !data.PrimaryDeviceId.IsNull() { + body, _ = sjson.Set(body, "primary.id", data.PrimaryDeviceId.ValueString()) + } + if !data.SecondaryDeviceId.IsNull() { + body, _ = sjson.Set(body, "secondary.id", data.SecondaryDeviceId.ValueString()) + } + if !data.IsEncryptionEnabled.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.isEncryptionEnabled", data.IsEncryptionEnabled.ValueBool()) + } + if !data.UseSameLinkForFailovers.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.useSameLinkForFailovers", data.UseSameLinkForFailovers.ValueBool()) + } + if !data.SharedKey.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.sharedKey", data.SharedKey.ValueString()) + } + if !data.EncKeyGenerationScheme.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.encKeyGenerationScheme", data.EncKeyGenerationScheme.ValueString()) + } + if !data.LanFailoverStandbyIp.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.standbyIP", data.LanFailoverStandbyIp.ValueString()) + } + if !data.LanFailoverActiveIp.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.activeIP", data.LanFailoverActiveIp.ValueString()) + } + if !data.LanFailoverName.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.logicalName", data.LanFailoverName.ValueString()) + } + if !data.LanFailoverSubnetMask.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.subnetMask", data.LanFailoverSubnetMask.ValueString()) + } + if !data.LanFailoverIpv6Addr.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.useIPv6Address", data.LanFailoverIpv6Addr.ValueBool()) + } + if !data.LanFailoverInterfaceName.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.interfaceObject.name", data.LanFailoverInterfaceName.ValueString()) + } + if !data.LanFailoverInterfaceId.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.interfaceObject.id", data.LanFailoverInterfaceId.ValueString()) + } + if !data.LanFailoverInterfaceType.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.interfaceObject.type", data.LanFailoverInterfaceType.ValueString()) + } + if !data.StatefulFailoverStandbyIp.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.standbyIP", data.StatefulFailoverStandbyIp.ValueString()) + } + if !data.StatefulFailoverActiveIp.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.activeIP", data.StatefulFailoverActiveIp.ValueString()) + } + if !data.StatefulFailoverName.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.logicalName", data.StatefulFailoverName.ValueString()) + } + if !data.StatefulFailoverSubnetMask.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.subnetMask", data.StatefulFailoverSubnetMask.ValueString()) + } + if !data.StatefulFailoverIpv6Addr.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.useIPv6Address", data.StatefulFailoverIpv6Addr.ValueBool()) + } + if !data.StatefulFailoverInterfaceName.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.interfaceObject.name", data.StatefulFailoverInterfaceName.ValueString()) + } + if !data.StatefulFailoverInterfaceId.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.interfaceObject.id", data.StatefulFailoverInterfaceId.ValueString()) + } + if !data.StatefulFailoverInterfaceType.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.statefulFailover.interfaceObject.type", data.StatefulFailoverInterfaceType.ValueString()) + } + if !data.Action.IsNull() { + body, _ = sjson.Set(body, "action", data.Action.ValueString()) + } + if !data.ForceBreak.IsNull() { + body, _ = sjson.Set(body, "forceBreak", data.ForceBreak.ValueBool()) + } + return body +} + +// End of section. //template:end toBody + +// Section below is generated&owned by "gen/generator.go". //template:begin fromBody + +func (data *DeviceHAPairs) 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("primary.id"); value.Exists() { + data.PrimaryDeviceId = types.StringValue(value.String()) + } else { + data.PrimaryDeviceId = types.StringNull() + } + if value := res.Get("secondary.id"); value.Exists() { + data.SecondaryDeviceId = types.StringValue(value.String()) + } else { + data.SecondaryDeviceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.isEncryptionEnabled"); value.Exists() { + data.IsEncryptionEnabled = types.BoolValue(value.Bool()) + } else { + data.IsEncryptionEnabled = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.useSameLinkForFailovers"); value.Exists() { + data.UseSameLinkForFailovers = types.BoolValue(value.Bool()) + } else { + data.UseSameLinkForFailovers = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.sharedKey"); value.Exists() { + data.SharedKey = types.StringValue(value.String()) + } else { + data.SharedKey = types.StringNull() + } + if value := res.Get("ftdHABootstrap.encKeyGenerationScheme"); value.Exists() { + data.EncKeyGenerationScheme = types.StringValue(value.String()) + } else { + data.EncKeyGenerationScheme = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.standbyIP"); value.Exists() { + data.LanFailoverStandbyIp = types.StringValue(value.String()) + } else { + data.LanFailoverStandbyIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.activeIP"); value.Exists() { + data.LanFailoverActiveIp = types.StringValue(value.String()) + } else { + data.LanFailoverActiveIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.logicalName"); value.Exists() { + data.LanFailoverName = types.StringValue(value.String()) + } else { + data.LanFailoverName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.subnetMask"); value.Exists() { + data.LanFailoverSubnetMask = types.StringValue(value.String()) + } else { + data.LanFailoverSubnetMask = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.useIPv6Address"); value.Exists() { + data.LanFailoverIpv6Addr = types.BoolValue(value.Bool()) + } else { + data.LanFailoverIpv6Addr = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.name"); value.Exists() { + data.LanFailoverInterfaceName = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.id"); value.Exists() { + data.LanFailoverInterfaceId = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.type"); value.Exists() { + data.LanFailoverInterfaceType = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceType = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.standbyIP"); value.Exists() { + data.StatefulFailoverStandbyIp = types.StringValue(value.String()) + } else { + data.StatefulFailoverStandbyIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.activeIP"); value.Exists() { + data.StatefulFailoverActiveIp = types.StringValue(value.String()) + } else { + data.StatefulFailoverActiveIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.logicalName"); value.Exists() { + data.StatefulFailoverName = types.StringValue(value.String()) + } else { + data.StatefulFailoverName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.subnetMask"); value.Exists() { + data.StatefulFailoverSubnetMask = types.StringValue(value.String()) + } else { + data.StatefulFailoverSubnetMask = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.useIPv6Address"); value.Exists() { + data.StatefulFailoverIpv6Addr = types.BoolValue(value.Bool()) + } else { + data.StatefulFailoverIpv6Addr = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.name"); value.Exists() { + data.StatefulFailoverInterfaceName = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.id"); value.Exists() { + data.StatefulFailoverInterfaceId = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.type"); value.Exists() { + data.StatefulFailoverInterfaceType = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceType = types.StringNull() + } + if value := res.Get("action"); value.Exists() { + data.Action = types.StringValue(value.String()) + } else { + data.Action = types.StringNull() + } + if value := res.Get("forceBreak"); value.Exists() { + data.ForceBreak = types.BoolValue(value.Bool()) + } else { + data.ForceBreak = types.BoolNull() + } +} + +// 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 *DeviceHAPairs) 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("primary.id"); value.Exists() && !data.PrimaryDeviceId.IsNull() { + data.PrimaryDeviceId = types.StringValue(value.String()) + } else { + data.PrimaryDeviceId = types.StringNull() + } + if value := res.Get("secondary.id"); value.Exists() && !data.SecondaryDeviceId.IsNull() { + data.SecondaryDeviceId = types.StringValue(value.String()) + } else { + data.SecondaryDeviceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.isEncryptionEnabled"); value.Exists() && !data.IsEncryptionEnabled.IsNull() { + data.IsEncryptionEnabled = types.BoolValue(value.Bool()) + } else { + data.IsEncryptionEnabled = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.useSameLinkForFailovers"); value.Exists() && !data.UseSameLinkForFailovers.IsNull() { + data.UseSameLinkForFailovers = types.BoolValue(value.Bool()) + } else { + data.UseSameLinkForFailovers = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.sharedKey"); value.Exists() && !data.SharedKey.IsNull() { + data.SharedKey = types.StringValue(value.String()) + } else { + data.SharedKey = types.StringNull() + } + if value := res.Get("ftdHABootstrap.encKeyGenerationScheme"); value.Exists() && !data.EncKeyGenerationScheme.IsNull() { + data.EncKeyGenerationScheme = types.StringValue(value.String()) + } else { + data.EncKeyGenerationScheme = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.standbyIP"); value.Exists() && !data.LanFailoverStandbyIp.IsNull() { + data.LanFailoverStandbyIp = types.StringValue(value.String()) + } else { + data.LanFailoverStandbyIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.activeIP"); value.Exists() && !data.LanFailoverActiveIp.IsNull() { + data.LanFailoverActiveIp = types.StringValue(value.String()) + } else { + data.LanFailoverActiveIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.logicalName"); value.Exists() && !data.LanFailoverName.IsNull() { + data.LanFailoverName = types.StringValue(value.String()) + } else { + data.LanFailoverName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.subnetMask"); value.Exists() && !data.LanFailoverSubnetMask.IsNull() { + data.LanFailoverSubnetMask = types.StringValue(value.String()) + } else { + data.LanFailoverSubnetMask = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.useIPv6Address"); value.Exists() && !data.LanFailoverIpv6Addr.IsNull() { + data.LanFailoverIpv6Addr = types.BoolValue(value.Bool()) + } else { + data.LanFailoverIpv6Addr = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.name"); value.Exists() && !data.LanFailoverInterfaceName.IsNull() { + data.LanFailoverInterfaceName = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.id"); value.Exists() && !data.LanFailoverInterfaceId.IsNull() { + data.LanFailoverInterfaceId = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.type"); value.Exists() && !data.LanFailoverInterfaceType.IsNull() { + data.LanFailoverInterfaceType = types.StringValue(value.String()) + } else { + data.LanFailoverInterfaceType = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.standbyIP"); value.Exists() && !data.StatefulFailoverStandbyIp.IsNull() { + data.StatefulFailoverStandbyIp = types.StringValue(value.String()) + } else { + data.StatefulFailoverStandbyIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.activeIP"); value.Exists() && !data.StatefulFailoverActiveIp.IsNull() { + data.StatefulFailoverActiveIp = types.StringValue(value.String()) + } else { + data.StatefulFailoverActiveIp = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.logicalName"); value.Exists() && !data.StatefulFailoverName.IsNull() { + data.StatefulFailoverName = types.StringValue(value.String()) + } else { + data.StatefulFailoverName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.subnetMask"); value.Exists() && !data.StatefulFailoverSubnetMask.IsNull() { + data.StatefulFailoverSubnetMask = types.StringValue(value.String()) + } else { + data.StatefulFailoverSubnetMask = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.useIPv6Address"); value.Exists() && !data.StatefulFailoverIpv6Addr.IsNull() { + data.StatefulFailoverIpv6Addr = types.BoolValue(value.Bool()) + } else { + data.StatefulFailoverIpv6Addr = types.BoolNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.name"); value.Exists() && !data.StatefulFailoverInterfaceName.IsNull() { + data.StatefulFailoverInterfaceName = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceName = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.id"); value.Exists() && !data.StatefulFailoverInterfaceId.IsNull() { + data.StatefulFailoverInterfaceId = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceId = types.StringNull() + } + if value := res.Get("ftdHABootstrap.statefulFailover.interfaceObject.type"); value.Exists() && !data.StatefulFailoverInterfaceType.IsNull() { + data.StatefulFailoverInterfaceType = types.StringValue(value.String()) + } else { + data.StatefulFailoverInterfaceType = types.StringNull() + } + if value := res.Get("action"); value.Exists() && !data.Action.IsNull() { + data.Action = types.StringValue(value.String()) + } else { + data.Action = types.StringNull() + } + if value := res.Get("forceBreak"); value.Exists() && !data.ForceBreak.IsNull() { + data.ForceBreak = types.BoolValue(value.Bool()) + } else { + data.ForceBreak = types.BoolNull() + } +} + +// 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 *DeviceHAPairs) fromBodyUnknowns(ctx context.Context, res gjson.Result) { +} + +// 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/provider.go b/internal/provider/provider.go index 9f14f035..10946d06 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -303,6 +303,7 @@ func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource NewExtendedACLResource, NewFQDNObjectResource, NewFQDNObjectsResource, + NewDeviceHAPairsResource, NewHostResource, NewHostsResource, NewICMPv4ObjectResource, @@ -352,6 +353,7 @@ func (p *FmcProvider) DataSources(ctx context.Context) []func() datasource.DataS NewExtendedACLDataSource, NewFQDNObjectDataSource, NewFQDNObjectsDataSource, + NewDeviceHAPairsDataSource, NewHostDataSource, NewHostsDataSource, NewICMPv4ObjectDataSource, diff --git a/internal/provider/resource_fmc_device_ha_pairs.go b/internal/provider/resource_fmc_device_ha_pairs.go new file mode 100644 index 00000000..fe6b6bd1 --- /dev/null +++ b/internal/provider/resource_fmc_device_ha_pairs.go @@ -0,0 +1,418 @@ +// 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" + "time" + + "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 = &DeviceHAPairsResource{} + _ resource.ResourceWithImportState = &DeviceHAPairsResource{} +) + +func NewDeviceHAPairsResource() resource.Resource { + return &DeviceHAPairsResource{} +} + +type DeviceHAPairsResource struct { + client *fmc.Client +} + +func (r *DeviceHAPairsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pairs" +} + +func (r *DeviceHAPairsResource) 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 Pairs.").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 access control policy.").String, + Required: true, + }, + "primary_device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of primary FTD in the HA Pair.").String, + Required: true, + }, + "secondary_device_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of secondary FTD in the HA Pair.").String, + Required: true, + }, + "is_encryption_enabled": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "use_same_link_for_failovers": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Required: true, + }, + "shared_key": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "enc_key_generation_scheme": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").AddStringEnumDescription("AUTO", "CUSTOM").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("AUTO", "CUSTOM"), + }, + }, + "lan_failover_standby_ip": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Required: true, + }, + "lan_failover_active_ip": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Required: true, + }, + "lan_failover_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Required: true, + }, + "lan_failover_subnet_mask": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "lan_failover_ipv6_addr": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "lan_failover_interface_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Name of physical interface").String, + Optional: true, + }, + "lan_failover_interface_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of physical interface.").String, + Required: true, + }, + "lan_failover_interface_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of physical interface.").String, + Optional: true, + }, + "stateful_failover_standby_ip": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "stateful_failover_active_ip": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "stateful_failover_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "stateful_failover_subnet_mask": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "stateful_failover_ipv6_addr": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("").String, + Optional: true, + }, + "stateful_failover_interface_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Name of physical interface").String, + Optional: true, + }, + "stateful_failover_interface_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of physical interface.").String, + Optional: true, + }, + "stateful_failover_interface_type": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Type of physical interface.").String, + Optional: true, + }, + "action": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch.").AddStringEnumDescription("SWITCH", "HABREAK").String, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("SWITCH", "HABREAK"), + }, + }, + "force_break": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("FTD HA Force Break option (PUT Option).").String, + Optional: true, + }, + }, + } +} + +func (r *DeviceHAPairsResource) 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 + +func (r *DeviceHAPairsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceHAPairs + + // 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, DeviceHAPairs{}) + 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 + } + // Adding code to poll object + taskID := res.Get("metadata.task.id").String() + tflog.Debug(ctx, fmt.Sprintf("%s: Async task initiated successfully", taskID)) + + const atom time.Duration = 5 * time.Second + // We need device's UUID, but it only shows after the task succeeds. Poll the task. + for i := time.Duration(0); i < 5*time.Minute; i += atom { + task, err := r.client.Get("/api/fmc_config/v1/domain/{DOMAIN_UUID}/job/taskstatuses/"+url.QueryEscape(taskID), reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to read object (GET), got error: %s, %s", err, task.String())) + return + } + stat := strings.ToUpper(task.Get("status").String()) + if stat == "FAILED" { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("API task for the new device failed: %s, %s", task.Get("message"), task.Get("description"))) + return + } + if stat != "PENDING" && stat != "RUNNING" { + break + } + time.Sleep(atom) + } + + check, err := r.client.Get(plan.getPath()) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to read object (GET), got error: %s, %s", err, check)) + return + } + name := "items.#(name==" + url.QueryEscape(plan.Name.ValueString()) + ").id" + id := check.Get(name).String() + plan.Id = types.StringValue(id) + if plan.Id.ValueString() == "" { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("No device named %q: %s", plan.Name.ValueString(), check)) + return + } + + // Ending code to poll object + // 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) +} + +// Section below is generated&owned by "gen/generator.go". //template:begin read + +func (r *DeviceHAPairsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceHAPairs + + // 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 *DeviceHAPairsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceHAPairs + + // 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 *DeviceHAPairsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceHAPairs + + // 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 *DeviceHAPairsResource) 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_device_ha_pairs_test.go b/internal/provider/resource_fmc_device_ha_pairs_test.go new file mode 100644 index 00000000..8a236b82 --- /dev/null +++ b/internal/provider/resource_fmc_device_ha_pairs_test.go @@ -0,0 +1,138 @@ +// 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 TestAccFmcDeviceHAPairs(t *testing.T) { + var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "name", "FTD_HA")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "primary_device_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "secondary_device_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "is_encryption_enabled", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "use_same_link_for_failovers", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "shared_key", "cisco123")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "enc_key_generation_scheme", "CUSTOM")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_name", "LAN-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_name", "Stateful-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_id", "")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "action", "SWITCH")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "force_break", "false")) + + var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceHAPairsConfig_minimum(), + }) + } + steps = append(steps, resource.TestStep{ + Config: testAccFmcDeviceHAPairsConfig_all(), + Check: resource.ComposeTestCheckFunc(checks...), + }) + steps = append(steps, resource.TestStep{ + ResourceName: "fmc_device_ha_pairs.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 testAccFmcDeviceHAPairsConfig_minimum() string { + config := `resource "fmc_device_ha_pairs" "test" {` + "\n" + config += ` name = "FTD_HA"` + "\n" + config += ` primary_device_id = ""` + "\n" + config += ` secondary_device_id = ""` + "\n" + config += ` use_same_link_for_failovers = false` + "\n" + config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" + config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" + config += ` lan_failover_interface_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 testAccFmcDeviceHAPairsConfig_all() string { + config := `resource "fmc_device_ha_pairs" "test" {` + "\n" + config += ` name = "FTD_HA"` + "\n" + config += ` primary_device_id = ""` + "\n" + config += ` secondary_device_id = ""` + "\n" + config += ` is_encryption_enabled = false` + "\n" + config += ` use_same_link_for_failovers = false` + "\n" + config += ` shared_key = "cisco123"` + "\n" + config += ` enc_key_generation_scheme = "CUSTOM"` + "\n" + config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" + config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" + config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_ipv6_addr = false` + "\n" + config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" + config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" + config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` stateful_failover_ipv6_addr = false` + "\n" + config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" + config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" + config += ` action = "SWITCH"` + "\n" + config += ` force_break = false` + "\n" + config += `}` + "\n" + return config +} + +// End of section. //template:end testAccConfigAll From 62afde194d8af73dc30b19d6215f276c8f2e610d Mon Sep 17 00:00:00 2001 From: kadadhic Date: Thu, 5 Dec 2024 23:14:30 +0530 Subject: [PATCH 2/6] improving ha --- .../{device_ha_pairs.md => device_ha_pair.md} | 18 ++-- .../{device_ha_pairs.md => device_ha_pair.md} | 33 +++--- .../fmc_device_ha_pair/data-source.tf | 3 + .../resources/fmc_device_ha_pair/import.sh | 1 + .../resources/fmc_device_ha_pair/resource.tf | 27 +++++ ..._availability.yaml => device_ha_pair.yaml} | 27 +++-- ...s.go => data_source_fmc_device_ha_pair.go} | 34 +++--- ...=> data_source_fmc_device_ha_pair_test.go} | 101 +++++++++--------- ...a_pairs.go => model_fmc_device_ha_pair.go} | 12 +-- internal/provider/provider.go | 4 +- ...airs.go => resource_fmc_device_ha_pair.go} | 48 ++++----- ...go => resource_fmc_device_ha_pair_test.go} | 87 ++++++++------- 12 files changed, 217 insertions(+), 178 deletions(-) rename docs/data-sources/{device_ha_pairs.md => device_ha_pair.md} (73%) rename docs/resources/{device_ha_pairs.md => device_ha_pair.md} (71%) create mode 100644 examples/data-sources/fmc_device_ha_pair/data-source.tf create mode 100644 examples/resources/fmc_device_ha_pair/import.sh create mode 100644 examples/resources/fmc_device_ha_pair/resource.tf rename gen/definitions/{high_availability.yaml => device_ha_pair.yaml} (84%) rename internal/provider/{data_source_fmc_device_ha_pairs.go => data_source_fmc_device_ha_pair.go} (86%) rename internal/provider/{data_source_fmc_device_ha_pairs_test.go => data_source_fmc_device_ha_pair_test.go} (60%) rename internal/provider/{model_fmc_device_ha_pairs.go => model_fmc_device_ha_pair.go} (98%) rename internal/provider/{resource_fmc_device_ha_pairs.go => resource_fmc_device_ha_pair.go} (87%) rename internal/provider/{resource_fmc_device_ha_pairs_test.go => resource_fmc_device_ha_pair_test.go} (62%) diff --git a/docs/data-sources/device_ha_pairs.md b/docs/data-sources/device_ha_pair.md similarity index 73% rename from docs/data-sources/device_ha_pairs.md rename to docs/data-sources/device_ha_pair.md index 6befd1da..31d6f430 100644 --- a/docs/data-sources/device_ha_pairs.md +++ b/docs/data-sources/device_ha_pair.md @@ -1,19 +1,19 @@ --- # generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "fmc_device_ha_pairs Data Source - terraform-provider-fmc" +page_title: "fmc_device_ha_pair Data Source - terraform-provider-fmc" subcategory: "Device" description: |- - This data source can read the Device HA Pairs. + This data source can read the Device HA Pair. --- -# fmc_device_ha_pairs (Data Source) +# fmc_device_ha_pair (Data Source) -This data source can read the Device HA Pairs. +This data source can read the Device HA Pair. ## Example Usage ```terraform -data "fmc_device_ha_pairs" "example" { +data "fmc_device_ha_pair" "example" { id = "76d24097-41c4-4558-a4d0-a8c07ac08470" } ``` @@ -32,9 +32,9 @@ data "fmc_device_ha_pairs" "example" { ### Read-Only - `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. -- `enc_key_generation_scheme` (String) +- `enc_key_generation_scheme` (String) Select the encyption key generation scheme. - `force_break` (Boolean) FTD HA Force Break option (PUT Option). -- `is_encryption_enabled` (Boolean) +- `is_encryption_enabled` (Boolean) Boolean field to enable encryption - `lan_failover_active_ip` (String) - `lan_failover_interface_id` (String) ID of physical interface. - `lan_failover_interface_type` (String) Type of physical interface. @@ -44,7 +44,7 @@ data "fmc_device_ha_pairs" "example" { - `lan_failover_subnet_mask` (String) - `primary_device_id` (String) ID of primary FTD in the HA Pair. - `secondary_device_id` (String) ID of secondary FTD in the HA Pair. -- `shared_key` (String) +- `shared_key` (String) Pass the unique shared key if needed. - `stateful_failover_active_ip` (String) - `stateful_failover_interface_id` (String) ID of physical interface. - `stateful_failover_interface_type` (String) Type of physical interface. @@ -52,4 +52,4 @@ data "fmc_device_ha_pairs" "example" { - `stateful_failover_name` (String) - `stateful_failover_standby_ip` (String) - `stateful_failover_subnet_mask` (String) -- `use_same_link_for_failovers` (Boolean) +- `use_same_link_for_failovers` (Boolean) Boolean field to enable same link for failovers diff --git a/docs/resources/device_ha_pairs.md b/docs/resources/device_ha_pair.md similarity index 71% rename from docs/resources/device_ha_pairs.md rename to docs/resources/device_ha_pair.md index 101bf78c..1667eac0 100644 --- a/docs/resources/device_ha_pairs.md +++ b/docs/resources/device_ha_pair.md @@ -1,22 +1,22 @@ --- # generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "fmc_device_ha_pairs Resource - terraform-provider-fmc" +page_title: "fmc_device_ha_pair Resource - terraform-provider-fmc" subcategory: "Device" description: |- - This resource can manage a Device HA Pairs. + This resource can manage a Device HA Pair. --- -# fmc_device_ha_pairs (Resource) +# fmc_device_ha_pair (Resource) -This resource can manage a Device HA Pairs. +This resource can manage a Device HA Pair. ## Example Usage ```terraform -resource "fmc_device_ha_pairs" "example" { +resource "fmc_device_ha_pair" "example" { name = "FTD_HA" - primary_device_id = "" - secondary_device_id = "" + 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" @@ -27,15 +27,15 @@ resource "fmc_device_ha_pairs" "example" { lan_failover_subnet_mask = "255.255.255.0" lan_failover_ipv6_addr = false lan_failover_interface_name = "GigabitEthernet0/0" - lan_failover_interface_id = "" + lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470" lan_failover_interface_type = "PhysicalInterface" - stateful_failover_standby_ip = "1.1.1.2" - stateful_failover_active_ip = "1.1.1.1" + 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 = "" + stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470" stateful_failover_interface_type = "PhysicalInterface" action = "SWITCH" force_break = false @@ -54,21 +54,22 @@ resource "fmc_device_ha_pairs" "example" { - `name` (String) The name of the access control policy. - `primary_device_id` (String) ID of primary FTD in the HA Pair. - `secondary_device_id` (String) ID of secondary FTD in the HA Pair. -- `use_same_link_for_failovers` (Boolean) +- `use_same_link_for_failovers` (Boolean) Boolean field to enable same link for failovers ### Optional - `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. - Choices: `SWITCH`, `HABREAK` - `domain` (String) The name of the FMC domain -- `enc_key_generation_scheme` (String) - Choices: `AUTO`, `CUSTOM` +- `enc_key_generation_scheme` (String) Select the encyption key generation scheme. + - Choices: `AUTO`, `CUSTOM` - `force_break` (Boolean) FTD HA Force Break option (PUT Option). -- `is_encryption_enabled` (Boolean) +- `is_encryption_enabled` (Boolean) Boolean field to enable encryption - `lan_failover_interface_name` (String) Name of physical interface - `lan_failover_interface_type` (String) Type of physical interface. - `lan_failover_ipv6_addr` (Boolean) - `lan_failover_subnet_mask` (String) -- `shared_key` (String) +- `shared_key` (String) Pass the unique shared key if needed. - `stateful_failover_active_ip` (String) - `stateful_failover_interface_id` (String) ID of physical interface. - `stateful_failover_interface_name` (String) Name of physical interface @@ -87,5 +88,5 @@ resource "fmc_device_ha_pairs" "example" { Import is supported using the following syntax: ```shell -terraform import fmc_device_ha_pairs.example "" +terraform import fmc_device_ha_pair.example "" ``` 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/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/gen/definitions/high_availability.yaml b/gen/definitions/device_ha_pair.yaml similarity index 84% rename from gen/definitions/high_availability.yaml rename to gen/definitions/device_ha_pair.yaml index fb46dde3..66b30df8 100644 --- a/gen/definitions/high_availability.yaml +++ b/gen/definitions/device_ha_pair.yaml @@ -1,5 +1,5 @@ --- -name: Device HA Pairs +name: Device HA Pair rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs data_source_name_query: true doc_category: Device @@ -11,6 +11,7 @@ attributes: example: FTD_HA - model_name: type type: String + description: Type of the resource (DeviceHAPair). value: DeviceHAPair - model_name: id type: String @@ -18,31 +19,37 @@ attributes: tf_name: primary_device_id data_path: [primary] description: ID of primary FTD in the HA Pair. - example: + example: 76d24097-41c4-4558-a4d0-a8c07ac08470 + test_value: var.device_id - model_name: id type: String mandatory: true tf_name: secondary_device_id data_path: [secondary] description: ID of secondary FTD in the HA Pair. - example: + example: 96d24097-41c4-4332-a4d0-a8c07ac08482 + test_value: var.device_id - model_name: isEncryptionEnabled type: Bool data_path: [ftdHABootstrap] + description: Boolean field to enable encryption example: false - model_name: useSameLinkForFailovers type: Bool mandatory: true data_path: [ftdHABootstrap] example: false + description: Boolean field to enable same link for failovers - model_name: sharedKey type: String data_path: [ftdHABootstrap] + description: Pass the unique shared key if needed. example: cisco123 - model_name: encKeyGenerationScheme type: String data_path: [ftdHABootstrap] - example: CUSTOM + description: Select the encyption key generation scheme. + example: "CUSTOM" enum_values: [ AUTO, CUSTOM ] - model_name: standbyIP type: String @@ -84,7 +91,7 @@ attributes: tf_name: lan_failover_interface_id data_path: [ftdHABootstrap,lanFailover,interfaceObject] description: ID of physical interface. - example: + example: 757kdgh5-41c4-4558-a4d0-a8c07ac08470 - model_name: type type: String tf_name: lan_failover_interface_type @@ -95,12 +102,12 @@ attributes: type: String tf_name: stateful_failover_standby_ip data_path: [ftdHABootstrap,statefulFailover] - example: "1.1.1.2" + example: "10.10.10.2" - model_name: activeIP tf_name: stateful_failover_active_ip type: String data_path: [ftdHABootstrap,statefulFailover] - example: "1.1.1.1" + example: "10.10.10.1" - model_name: logicalName type: String tf_name: stateful_failover_name @@ -127,7 +134,7 @@ attributes: tf_name: stateful_failover_interface_id data_path: [ftdHABootstrap,statefulFailover,interfaceObject] description: ID of physical interface. - example: + example: 76d24097-hj7r-7786-a4d0-a8c07ac08470 - model_name: type type: String tf_name: stateful_failover_interface_type @@ -138,8 +145,12 @@ attributes: type: String description: FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. enum_values: [ SWITCH, HABREAK ] + exclude_test: true example: SWITCH - model_name: forceBreak type: Bool description: FTD HA Force Break option (PUT Option). + exclude_test: true example: false +test_prerequisites: |- + variable "device_id" { default = null } // tests will set $TF_VAR_device_id \ No newline at end of file diff --git a/internal/provider/data_source_fmc_device_ha_pairs.go b/internal/provider/data_source_fmc_device_ha_pair.go similarity index 86% rename from internal/provider/data_source_fmc_device_ha_pairs.go rename to internal/provider/data_source_fmc_device_ha_pair.go index dc322616..cf4dd3e1 100644 --- a/internal/provider/data_source_fmc_device_ha_pairs.go +++ b/internal/provider/data_source_fmc_device_ha_pair.go @@ -39,26 +39,26 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ datasource.DataSource = &DeviceHAPairsDataSource{} - _ datasource.DataSourceWithConfigure = &DeviceHAPairsDataSource{} + _ datasource.DataSource = &DeviceHAPairDataSource{} + _ datasource.DataSourceWithConfigure = &DeviceHAPairDataSource{} ) -func NewDeviceHAPairsDataSource() datasource.DataSource { - return &DeviceHAPairsDataSource{} +func NewDeviceHAPairDataSource() datasource.DataSource { + return &DeviceHAPairDataSource{} } -type DeviceHAPairsDataSource struct { +type DeviceHAPairDataSource struct { client *fmc.Client } -func (d *DeviceHAPairsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_device_ha_pairs" +func (d *DeviceHAPairDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pair" } -func (d *DeviceHAPairsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { +func (d *DeviceHAPairDataSource) 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 Pairs.", + MarkdownDescription: "This data source can read the Device HA Pair.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -84,19 +84,19 @@ func (d *DeviceHAPairsDataSource) Schema(ctx context.Context, req datasource.Sch Computed: true, }, "is_encryption_enabled": schema.BoolAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Boolean field to enable encryption", Computed: true, }, "use_same_link_for_failovers": schema.BoolAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Boolean field to enable same link for failovers", Computed: true, }, "shared_key": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Pass the unique shared key if needed.", Computed: true, }, "enc_key_generation_scheme": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Select the encyption key generation scheme.", Computed: true, }, "lan_failover_standby_ip": schema.StringAttribute{ @@ -176,7 +176,7 @@ func (d *DeviceHAPairsDataSource) Schema(ctx context.Context, req datasource.Sch }, } } -func (d *DeviceHAPairsDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { +func (d *DeviceHAPairDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { return []datasource.ConfigValidator{ datasourcevalidator.ExactlyOneOf( path.MatchRoot("id"), @@ -185,7 +185,7 @@ func (d *DeviceHAPairsDataSource) ConfigValidators(ctx context.Context) []dataso } } -func (d *DeviceHAPairsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { +func (d *DeviceHAPairDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { if req.ProviderData == nil { return } @@ -197,8 +197,8 @@ func (d *DeviceHAPairsDataSource) Configure(_ context.Context, req datasource.Co // Section below is generated&owned by "gen/generator.go". //template:begin read -func (d *DeviceHAPairsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config DeviceHAPairs +func (d *DeviceHAPairDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config DeviceHAPair // Read config diags := req.Config.Get(ctx, &config) diff --git a/internal/provider/data_source_fmc_device_ha_pairs_test.go b/internal/provider/data_source_fmc_device_ha_pair_test.go similarity index 60% rename from internal/provider/data_source_fmc_device_ha_pairs_test.go rename to internal/provider/data_source_fmc_device_ha_pair_test.go index 414ba591..c6268e2f 100644 --- a/internal/provider/data_source_fmc_device_ha_pairs_test.go +++ b/internal/provider/data_source_fmc_device_ha_pair_test.go @@ -28,43 +28,39 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource -func TestAccDataSourceFmcDeviceHAPairs(t *testing.T) { +func TestAccDataSourceFmcDeviceHAPair(t *testing.T) { var checks []resource.TestCheckFunc - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "name", "FTD_HA")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "primary_device_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "secondary_device_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "is_encryption_enabled", "false")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "use_same_link_for_failovers", "false")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "shared_key", "cisco123")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "enc_key_generation_scheme", "CUSTOM")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_standby_ip", "1.1.1.2")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_active_ip", "1.1.1.1")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_name", "LAN-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_subnet_mask", "255.255.255.0")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_ipv6_addr", "false")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "lan_failover_interface_type", "PhysicalInterface")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_standby_ip", "1.1.1.2")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_active_ip", "1.1.1.1")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_name", "Stateful-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_subnet_mask", "255.255.255.0")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_ipv6_addr", "false")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "stateful_failover_interface_type", "PhysicalInterface")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "action", "SWITCH")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pairs.test", "force_break", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "name", "FTD_HA")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "is_encryption_enabled", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "use_same_link_for_failovers", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "shared_key", "cisco123")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "enc_key_generation_scheme", "CUSTOM")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_standby_ip", "10.10.10.2")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_active_ip", "10.10.10.1")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_name", "Stateful-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_interface_id", "76d24097-hj7r-7786-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_interface_type", "PhysicalInterface")) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccDataSourceFmcDeviceHAPairsConfig(), + Config: testAccDataSourceFmcDeviceHAPairPrerequisitesConfig + testAccDataSourceFmcDeviceHAPairConfig(), Check: resource.ComposeTestCheckFunc(checks...), }, { - Config: testAccNamedDataSourceFmcDeviceHAPairsConfig(), + Config: testAccDataSourceFmcDeviceHAPairPrerequisitesConfig + testAccNamedDataSourceFmcDeviceHAPairConfig(), Check: resource.ComposeTestCheckFunc(checks...), }, }, @@ -74,15 +70,20 @@ func TestAccDataSourceFmcDeviceHAPairs(t *testing.T) { // End of section. //template:end testAccDataSource // Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccDataSourceFmcDeviceHAPairPrerequisitesConfig = ` +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 testAccDataSourceFmcDeviceHAPairsConfig() string { - config := `resource "fmc_device_ha_pairs" "test" {` + "\n" +func testAccDataSourceFmcDeviceHAPairConfig() string { + config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" - config += ` primary_device_id = ""` + "\n" - config += ` secondary_device_id = ""` + "\n" + config += ` primary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -93,33 +94,31 @@ func testAccDataSourceFmcDeviceHAPairsConfig() string { config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" - config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_standby_ip = "10.10.10.2"` + "\n" + config += ` stateful_failover_active_ip = "10.10.10.1"` + "\n" config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` stateful_failover_ipv6_addr = false` + "\n" config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470"` + "\n" config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` action = "SWITCH"` + "\n" - config += ` force_break = false` + "\n" config += `}` + "\n" config += ` - data "fmc_device_ha_pairs" "test" { - id = fmc_device_ha_pairs.test.id + data "fmc_device_ha_pair" "test" { + id = fmc_device_ha_pair.test.id } ` return config } -func testAccNamedDataSourceFmcDeviceHAPairsConfig() string { - config := `resource "fmc_device_ha_pairs" "test" {` + "\n" +func testAccNamedDataSourceFmcDeviceHAPairConfig() string { + config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" - config += ` primary_device_id = ""` + "\n" - config += ` secondary_device_id = ""` + "\n" + config += ` primary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -130,23 +129,21 @@ func testAccNamedDataSourceFmcDeviceHAPairsConfig() string { config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" - config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_standby_ip = "10.10.10.2"` + "\n" + config += ` stateful_failover_active_ip = "10.10.10.1"` + "\n" config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` stateful_failover_ipv6_addr = false` + "\n" config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470"` + "\n" config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` action = "SWITCH"` + "\n" - config += ` force_break = false` + "\n" config += `}` + "\n" config += ` - data "fmc_device_ha_pairs" "test" { - name = fmc_device_ha_pairs.test.name + data "fmc_device_ha_pair" "test" { + name = fmc_device_ha_pair.test.name } ` return config diff --git a/internal/provider/model_fmc_device_ha_pairs.go b/internal/provider/model_fmc_device_ha_pair.go similarity index 98% rename from internal/provider/model_fmc_device_ha_pairs.go rename to internal/provider/model_fmc_device_ha_pair.go index d792a3e5..8214cb4b 100644 --- a/internal/provider/model_fmc_device_ha_pairs.go +++ b/internal/provider/model_fmc_device_ha_pair.go @@ -30,7 +30,7 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin types -type DeviceHAPairs struct { +type DeviceHAPair struct { Id types.String `tfsdk:"id"` Domain types.String `tfsdk:"domain"` Name types.String `tfsdk:"name"` @@ -64,7 +64,7 @@ type DeviceHAPairs struct { // Section below is generated&owned by "gen/generator.go". //template:begin getPath -func (data DeviceHAPairs) getPath() string { +func (data DeviceHAPair) getPath() string { return "/api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs" } @@ -72,7 +72,7 @@ func (data DeviceHAPairs) getPath() string { // Section below is generated&owned by "gen/generator.go". //template:begin toBody -func (data DeviceHAPairs) toBody(ctx context.Context, state DeviceHAPairs) string { +func (data DeviceHAPair) toBody(ctx context.Context, state DeviceHAPair) string { body := "" if data.Id.ValueString() != "" { body, _ = sjson.Set(body, "id", data.Id.ValueString()) @@ -160,7 +160,7 @@ func (data DeviceHAPairs) toBody(ctx context.Context, state DeviceHAPairs) strin // Section below is generated&owned by "gen/generator.go". //template:begin fromBody -func (data *DeviceHAPairs) fromBody(ctx context.Context, res gjson.Result) { +func (data *DeviceHAPair) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("name"); value.Exists() { data.Name = types.StringValue(value.String()) } else { @@ -296,7 +296,7 @@ func (data *DeviceHAPairs) fromBody(ctx context.Context, res gjson.Result) { // 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 *DeviceHAPairs) fromBodyPartial(ctx context.Context, res gjson.Result) { +func (data *DeviceHAPair) fromBodyPartial(ctx context.Context, res gjson.Result) { if value := res.Get("name"); value.Exists() && !data.Name.IsNull() { data.Name = types.StringValue(value.String()) } else { @@ -430,7 +430,7 @@ func (data *DeviceHAPairs) 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 *DeviceHAPairs) fromBodyUnknowns(ctx context.Context, res gjson.Result) { +func (data *DeviceHAPair) fromBodyUnknowns(ctx context.Context, res gjson.Result) { } // End of section. //template:end fromBodyUnknowns diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 10946d06..31fbd50d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -290,6 +290,7 @@ func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource return []func() resource.Resource{ NewAccessControlPolicyResource, NewDeviceResource, + NewDeviceHAPairResource, NewDeviceIPv4StaticRouteResource, NewDeviceIPv6StaticRouteResource, NewDevicePhysicalInterfaceResource, @@ -303,7 +304,6 @@ func (p *FmcProvider) Resources(ctx context.Context) []func() resource.Resource NewExtendedACLResource, NewFQDNObjectResource, NewFQDNObjectsResource, - NewDeviceHAPairsResource, NewHostResource, NewHostsResource, NewICMPv4ObjectResource, @@ -340,6 +340,7 @@ func (p *FmcProvider) DataSources(ctx context.Context) []func() datasource.DataS return []func() datasource.DataSource{ NewAccessControlPolicyDataSource, NewDeviceDataSource, + NewDeviceHAPairDataSource, NewDeviceIPv4StaticRouteDataSource, NewDeviceIPv6StaticRouteDataSource, NewDevicePhysicalInterfaceDataSource, @@ -353,7 +354,6 @@ func (p *FmcProvider) DataSources(ctx context.Context) []func() datasource.DataS NewExtendedACLDataSource, NewFQDNObjectDataSource, NewFQDNObjectsDataSource, - NewDeviceHAPairsDataSource, NewHostDataSource, NewHostsDataSource, NewICMPv4ObjectDataSource, diff --git a/internal/provider/resource_fmc_device_ha_pairs.go b/internal/provider/resource_fmc_device_ha_pair.go similarity index 87% rename from internal/provider/resource_fmc_device_ha_pairs.go rename to internal/provider/resource_fmc_device_ha_pair.go index fe6b6bd1..6ca82fb8 100644 --- a/internal/provider/resource_fmc_device_ha_pairs.go +++ b/internal/provider/resource_fmc_device_ha_pair.go @@ -44,26 +44,26 @@ import ( // Ensure provider defined types fully satisfy framework interfaces var ( - _ resource.Resource = &DeviceHAPairsResource{} - _ resource.ResourceWithImportState = &DeviceHAPairsResource{} + _ resource.Resource = &DeviceHAPairResource{} + _ resource.ResourceWithImportState = &DeviceHAPairResource{} ) -func NewDeviceHAPairsResource() resource.Resource { - return &DeviceHAPairsResource{} +func NewDeviceHAPairResource() resource.Resource { + return &DeviceHAPairResource{} } -type DeviceHAPairsResource struct { +type DeviceHAPairResource struct { client *fmc.Client } -func (r *DeviceHAPairsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_device_ha_pairs" +func (r *DeviceHAPairResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_device_ha_pair" } -func (r *DeviceHAPairsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *DeviceHAPairResource) 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 Pairs.").String, + MarkdownDescription: helpers.NewAttributeDescription("This resource can manage a Device HA Pair.").String, Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -93,19 +93,19 @@ func (r *DeviceHAPairsResource) Schema(ctx context.Context, req resource.SchemaR Required: true, }, "is_encryption_enabled": schema.BoolAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("").String, + MarkdownDescription: helpers.NewAttributeDescription("Boolean field to enable encryption").String, Optional: true, }, "use_same_link_for_failovers": schema.BoolAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("").String, + MarkdownDescription: helpers.NewAttributeDescription("Boolean field to enable same link for failovers").String, Required: true, }, "shared_key": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("").String, + MarkdownDescription: helpers.NewAttributeDescription("Pass the unique shared key if needed.").String, Optional: true, }, "enc_key_generation_scheme": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("").AddStringEnumDescription("AUTO", "CUSTOM").String, + MarkdownDescription: helpers.NewAttributeDescription("Select the encyption key generation scheme.").AddStringEnumDescription("AUTO", "CUSTOM").String, Optional: true, Validators: []validator.String{ stringvalidator.OneOf("AUTO", "CUSTOM"), @@ -190,7 +190,7 @@ func (r *DeviceHAPairsResource) Schema(ctx context.Context, req resource.SchemaR } } -func (r *DeviceHAPairsResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { +func (r *DeviceHAPairResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { if req.ProviderData == nil { return } @@ -200,8 +200,8 @@ func (r *DeviceHAPairsResource) Configure(_ context.Context, req resource.Config // End of section. //template:end model -func (r *DeviceHAPairsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var plan DeviceHAPairs +func (r *DeviceHAPairResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan DeviceHAPair // Read plan diags := req.Plan.Get(ctx, &plan) @@ -218,7 +218,7 @@ func (r *DeviceHAPairsResource) Create(ctx context.Context, req resource.CreateR tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString())) // Create object - body := plan.toBody(ctx, DeviceHAPairs{}) + body := plan.toBody(ctx, DeviceHAPair{}) 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())) @@ -274,8 +274,8 @@ func (r *DeviceHAPairsResource) Create(ctx context.Context, req resource.CreateR // Section below is generated&owned by "gen/generator.go". //template:begin read -func (r *DeviceHAPairsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state DeviceHAPairs +func (r *DeviceHAPairResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state DeviceHAPair // Read state diags := req.State.Get(ctx, &state) @@ -326,8 +326,8 @@ func (r *DeviceHAPairsResource) Read(ctx context.Context, req resource.ReadReque // Section below is generated&owned by "gen/generator.go". //template:begin update -func (r *DeviceHAPairsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan, state DeviceHAPairs +func (r *DeviceHAPairResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state DeviceHAPair // Read plan diags := req.Plan.Get(ctx, &plan) @@ -366,8 +366,8 @@ func (r *DeviceHAPairsResource) Update(ctx context.Context, req resource.UpdateR // Section below is generated&owned by "gen/generator.go". //template:begin delete -func (r *DeviceHAPairsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state DeviceHAPairs +func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state DeviceHAPair // Read state diags := req.State.Get(ctx, &state) @@ -397,7 +397,7 @@ func (r *DeviceHAPairsResource) Delete(ctx context.Context, req resource.DeleteR // Section below is generated&owned by "gen/generator.go". //template:begin import -func (r *DeviceHAPairsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *DeviceHAPairResource) 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) diff --git a/internal/provider/resource_fmc_device_ha_pairs_test.go b/internal/provider/resource_fmc_device_ha_pair_test.go similarity index 62% rename from internal/provider/resource_fmc_device_ha_pairs_test.go rename to internal/provider/resource_fmc_device_ha_pair_test.go index 8a236b82..d10de1d4 100644 --- a/internal/provider/resource_fmc_device_ha_pairs_test.go +++ b/internal/provider/resource_fmc_device_ha_pair_test.go @@ -29,46 +29,42 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAcc -func TestAccFmcDeviceHAPairs(t *testing.T) { +func TestAccFmcDeviceHAPair(t *testing.T) { var checks []resource.TestCheckFunc - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "name", "FTD_HA")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "primary_device_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "secondary_device_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "is_encryption_enabled", "false")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "use_same_link_for_failovers", "false")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "shared_key", "cisco123")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "enc_key_generation_scheme", "CUSTOM")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_standby_ip", "1.1.1.2")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_active_ip", "1.1.1.1")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_name", "LAN-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_subnet_mask", "255.255.255.0")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_ipv6_addr", "false")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "lan_failover_interface_type", "PhysicalInterface")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_standby_ip", "1.1.1.2")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_active_ip", "1.1.1.1")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_name", "Stateful-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_subnet_mask", "255.255.255.0")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_ipv6_addr", "false")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_id", "")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "stateful_failover_interface_type", "PhysicalInterface")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "action", "SWITCH")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pairs.test", "force_break", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "name", "FTD_HA")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "is_encryption_enabled", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "use_same_link_for_failovers", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "shared_key", "cisco123")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "enc_key_generation_scheme", "CUSTOM")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_type", "PhysicalInterface")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_standby_ip", "10.10.10.2")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_active_ip", "10.10.10.1")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_name", "Stateful-INTERFACE")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_ipv6_addr", "false")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_interface_name", "GigabitEthernet0/0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_interface_id", "76d24097-hj7r-7786-a4d0-a8c07ac08470")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_interface_type", "PhysicalInterface")) var steps []resource.TestStep if os.Getenv("SKIP_MINIMUM_TEST") == "" { steps = append(steps, resource.TestStep{ - Config: testAccFmcDeviceHAPairsConfig_minimum(), + Config: testAccFmcDeviceHAPairPrerequisitesConfig + testAccFmcDeviceHAPairConfig_minimum(), }) } steps = append(steps, resource.TestStep{ - Config: testAccFmcDeviceHAPairsConfig_all(), + Config: testAccFmcDeviceHAPairPrerequisitesConfig + testAccFmcDeviceHAPairConfig_all(), Check: resource.ComposeTestCheckFunc(checks...), }) steps = append(steps, resource.TestStep{ - ResourceName: "fmc_device_ha_pairs.test", + ResourceName: "fmc_device_ha_pair.test", ImportState: true, }) @@ -82,20 +78,25 @@ func TestAccFmcDeviceHAPairs(t *testing.T) { // End of section. //template:end testAcc // Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites + +const testAccFmcDeviceHAPairPrerequisitesConfig = ` +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 testAccFmcDeviceHAPairsConfig_minimum() string { - config := `resource "fmc_device_ha_pairs" "test" {` + "\n" +func testAccFmcDeviceHAPairConfig_minimum() string { + config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" - config += ` primary_device_id = ""` + "\n" - config += ` secondary_device_id = ""` + "\n" + config += ` primary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_id` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" - config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" config += `}` + "\n" return config } @@ -104,11 +105,11 @@ func testAccFmcDeviceHAPairsConfig_minimum() string { // Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll -func testAccFmcDeviceHAPairsConfig_all() string { - config := `resource "fmc_device_ha_pairs" "test" {` + "\n" +func testAccFmcDeviceHAPairConfig_all() string { + config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" - config += ` primary_device_id = ""` + "\n" - config += ` secondary_device_id = ""` + "\n" + config += ` primary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -119,18 +120,16 @@ func testAccFmcDeviceHAPairsConfig_all() string { config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` lan_failover_interface_id = ""` + "\n" + config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` stateful_failover_standby_ip = "1.1.1.2"` + "\n" - config += ` stateful_failover_active_ip = "1.1.1.1"` + "\n" + config += ` stateful_failover_standby_ip = "10.10.10.2"` + "\n" + config += ` stateful_failover_active_ip = "10.10.10.1"` + "\n" config += ` stateful_failover_name = "Stateful-INTERFACE"` + "\n" config += ` stateful_failover_subnet_mask = "255.255.255.0"` + "\n" config += ` stateful_failover_ipv6_addr = false` + "\n" config += ` stateful_failover_interface_name = "GigabitEthernet0/0"` + "\n" - config += ` stateful_failover_interface_id = ""` + "\n" + config += ` stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470"` + "\n" config += ` stateful_failover_interface_type = "PhysicalInterface"` + "\n" - config += ` action = "SWITCH"` + "\n" - config += ` force_break = false` + "\n" config += `}` + "\n" return config } From 50c84638608f0b9b61c4e82759ecf969187da890 Mon Sep 17 00:00:00 2001 From: kadadhic Date: Tue, 10 Dec 2024 11:23:30 +0530 Subject: [PATCH 3/6] updating ha-pair feature --- docs/data-sources/device_ha_pair.md | 4 ++-- docs/resources/device_ha_pair.md | 10 +++++----- .../resources/fmc_device_ha_pair/resource.tf | 2 +- gen/definitions/device_ha_pair.yaml | 9 ++++++--- .../data_source_fmc_device_ha_pair.go | 4 ++-- .../data_source_fmc_device_ha_pair_test.go | 14 ++++++++----- internal/provider/model_fmc_device_ha_pair.go | 20 +++++++++---------- .../provider/resource_fmc_device_ha_pair.go | 17 ++++++++-------- .../resource_fmc_device_ha_pair_test.go | 12 +++++++---- 9 files changed, 51 insertions(+), 41 deletions(-) diff --git a/docs/data-sources/device_ha_pair.md b/docs/data-sources/device_ha_pair.md index 31d6f430..25eb04cf 100644 --- a/docs/data-sources/device_ha_pair.md +++ b/docs/data-sources/device_ha_pair.md @@ -26,7 +26,7 @@ data "fmc_device_ha_pair" "example" { - `domain` (String) The name of the FMC domain - `id` (String) The id of the object - `lan_failover_interface_name` (String) Name of physical interface -- `name` (String) The name of the access control policy. +- `name` (String) The name of the High Availability Pair. - `stateful_failover_interface_name` (String) Name of physical interface ### Read-Only @@ -40,8 +40,8 @@ data "fmc_device_ha_pair" "example" { - `lan_failover_interface_type` (String) Type of physical interface. - `lan_failover_ipv6_addr` (Boolean) - `lan_failover_name` (String) +- `lan_failover_netmask` (String) - `lan_failover_standby_ip` (String) -- `lan_failover_subnet_mask` (String) - `primary_device_id` (String) ID of primary FTD in the HA Pair. - `secondary_device_id` (String) ID of secondary FTD in the HA Pair. - `shared_key` (String) Pass the unique shared key if needed. diff --git a/docs/resources/device_ha_pair.md b/docs/resources/device_ha_pair.md index 1667eac0..9b951dda 100644 --- a/docs/resources/device_ha_pair.md +++ b/docs/resources/device_ha_pair.md @@ -24,7 +24,7 @@ resource "fmc_device_ha_pair" "example" { 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_netmask = "255.255.255.0" lan_failover_ipv6_addr = false lan_failover_interface_name = "GigabitEthernet0/0" lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470" @@ -49,9 +49,10 @@ resource "fmc_device_ha_pair" "example" { - `lan_failover_active_ip` (String) - `lan_failover_interface_id` (String) ID of physical interface. +- `lan_failover_interface_type` (String) Type of physical interface. - `lan_failover_name` (String) - `lan_failover_standby_ip` (String) -- `name` (String) The name of the access control policy. +- `name` (String) The name of the High Availability Pair. - `primary_device_id` (String) ID of primary FTD in the HA Pair. - `secondary_device_id` (String) ID of secondary FTD in the HA Pair. - `use_same_link_for_failovers` (Boolean) Boolean field to enable same link for failovers @@ -66,9 +67,8 @@ resource "fmc_device_ha_pair" "example" { - `force_break` (Boolean) FTD HA Force Break option (PUT Option). - `is_encryption_enabled` (Boolean) Boolean field to enable encryption - `lan_failover_interface_name` (String) Name of physical interface -- `lan_failover_interface_type` (String) Type of physical interface. -- `lan_failover_ipv6_addr` (Boolean) -- `lan_failover_subnet_mask` (String) +- `lan_failover_ipv6_addr` (Boolean) - Default value: `false` +- `lan_failover_netmask` (String) - `shared_key` (String) Pass the unique shared key if needed. - `stateful_failover_active_ip` (String) - `stateful_failover_interface_id` (String) ID of physical interface. diff --git a/examples/resources/fmc_device_ha_pair/resource.tf b/examples/resources/fmc_device_ha_pair/resource.tf index 62255af9..6387e239 100644 --- a/examples/resources/fmc_device_ha_pair/resource.tf +++ b/examples/resources/fmc_device_ha_pair/resource.tf @@ -9,7 +9,7 @@ resource "fmc_device_ha_pair" "example" { 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_netmask = "255.255.255.0" lan_failover_ipv6_addr = false lan_failover_interface_name = "GigabitEthernet0/0" lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470" diff --git a/gen/definitions/device_ha_pair.yaml b/gen/definitions/device_ha_pair.yaml index 66b30df8..e95f7355 100644 --- a/gen/definitions/device_ha_pair.yaml +++ b/gen/definitions/device_ha_pair.yaml @@ -3,11 +3,12 @@ name: Device HA Pair rest_endpoint: /api/fmc_config/v1/domain/{DOMAIN_UUID}/devicehapairs/ftddevicehapairs data_source_name_query: true doc_category: Device +test_tags: [TF_VAR_device_id, TF_VAR_device_2_id] attributes: - model_name: name type: String mandatory: true - description: The name of the access control policy. + description: The name of the High Availability Pair. example: FTD_HA - model_name: type type: String @@ -28,7 +29,7 @@ attributes: data_path: [secondary] description: ID of secondary FTD in the HA Pair. example: 96d24097-41c4-4332-a4d0-a8c07ac08482 - test_value: var.device_id + test_value: var.device_2_id - model_name: isEncryptionEnabled type: Bool data_path: [ftdHABootstrap] @@ -71,12 +72,13 @@ attributes: example: LAN-INTERFACE - model_name: subnetMask type: String - tf_name: lan_failover_subnet_mask + tf_name: lan_failover_netmask data_path: [ftdHABootstrap,lanFailover] example: "255.255.255.0" - model_name: useIPv6Address type: Bool tf_name: lan_failover_ipv6_addr + default_value: false data_path: [ftdHABootstrap,lanFailover] example: false - model_name: name @@ -94,6 +96,7 @@ attributes: example: 757kdgh5-41c4-4558-a4d0-a8c07ac08470 - model_name: type type: String + mandatory: true tf_name: lan_failover_interface_type data_path: [ftdHABootstrap,lanFailover,interfaceObject] description: Type of physical interface. diff --git a/internal/provider/data_source_fmc_device_ha_pair.go b/internal/provider/data_source_fmc_device_ha_pair.go index cf4dd3e1..1cf3f457 100644 --- a/internal/provider/data_source_fmc_device_ha_pair.go +++ b/internal/provider/data_source_fmc_device_ha_pair.go @@ -71,7 +71,7 @@ func (d *DeviceHAPairDataSource) Schema(ctx context.Context, req datasource.Sche Optional: true, }, "name": schema.StringAttribute{ - MarkdownDescription: "The name of the access control policy.", + MarkdownDescription: "The name of the High Availability Pair.", Optional: true, Computed: true, }, @@ -111,7 +111,7 @@ func (d *DeviceHAPairDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "", Computed: true, }, - "lan_failover_subnet_mask": schema.StringAttribute{ + "lan_failover_netmask": schema.StringAttribute{ MarkdownDescription: "", Computed: true, }, diff --git a/internal/provider/data_source_fmc_device_ha_pair_test.go b/internal/provider/data_source_fmc_device_ha_pair_test.go index c6268e2f..489b7079 100644 --- a/internal/provider/data_source_fmc_device_ha_pair_test.go +++ b/internal/provider/data_source_fmc_device_ha_pair_test.go @@ -19,6 +19,7 @@ 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" @@ -29,6 +30,9 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource func TestAccDataSourceFmcDeviceHAPair(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" && os.Getenv("TF_VAR_device_2_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id or TF_VAR_device_2_id") + } var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "name", "FTD_HA")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "is_encryption_enabled", "false")) @@ -38,7 +42,7 @@ func TestAccDataSourceFmcDeviceHAPair(t *testing.T) { checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_netmask", "255.255.255.0")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) @@ -83,7 +87,7 @@ func testAccDataSourceFmcDeviceHAPairConfig() string { config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" config += ` primary_device_id = var.device_id` + "\n" - config += ` secondary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_2_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -91,7 +95,7 @@ func testAccDataSourceFmcDeviceHAPairConfig() string { config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" - config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_netmask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" @@ -118,7 +122,7 @@ func testAccNamedDataSourceFmcDeviceHAPairConfig() string { config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" config += ` primary_device_id = var.device_id` + "\n" - config += ` secondary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_2_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -126,7 +130,7 @@ func testAccNamedDataSourceFmcDeviceHAPairConfig() string { config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" - config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_netmask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" diff --git a/internal/provider/model_fmc_device_ha_pair.go b/internal/provider/model_fmc_device_ha_pair.go index 8214cb4b..02347cf1 100644 --- a/internal/provider/model_fmc_device_ha_pair.go +++ b/internal/provider/model_fmc_device_ha_pair.go @@ -43,7 +43,7 @@ type DeviceHAPair struct { LanFailoverStandbyIp types.String `tfsdk:"lan_failover_standby_ip"` LanFailoverActiveIp types.String `tfsdk:"lan_failover_active_ip"` LanFailoverName types.String `tfsdk:"lan_failover_name"` - LanFailoverSubnetMask types.String `tfsdk:"lan_failover_subnet_mask"` + LanFailoverNetmask types.String `tfsdk:"lan_failover_netmask"` LanFailoverIpv6Addr types.Bool `tfsdk:"lan_failover_ipv6_addr"` LanFailoverInterfaceName types.String `tfsdk:"lan_failover_interface_name"` LanFailoverInterfaceId types.String `tfsdk:"lan_failover_interface_id"` @@ -108,8 +108,8 @@ func (data DeviceHAPair) toBody(ctx context.Context, state DeviceHAPair) string if !data.LanFailoverName.IsNull() { body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.logicalName", data.LanFailoverName.ValueString()) } - if !data.LanFailoverSubnetMask.IsNull() { - body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.subnetMask", data.LanFailoverSubnetMask.ValueString()) + if !data.LanFailoverNetmask.IsNull() { + body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.subnetMask", data.LanFailoverNetmask.ValueString()) } if !data.LanFailoverIpv6Addr.IsNull() { body, _ = sjson.Set(body, "ftdHABootstrap.lanFailover.useIPv6Address", data.LanFailoverIpv6Addr.ValueBool()) @@ -212,14 +212,14 @@ func (data *DeviceHAPair) fromBody(ctx context.Context, res gjson.Result) { data.LanFailoverName = types.StringNull() } if value := res.Get("ftdHABootstrap.lanFailover.subnetMask"); value.Exists() { - data.LanFailoverSubnetMask = types.StringValue(value.String()) + data.LanFailoverNetmask = types.StringValue(value.String()) } else { - data.LanFailoverSubnetMask = types.StringNull() + data.LanFailoverNetmask = types.StringNull() } if value := res.Get("ftdHABootstrap.lanFailover.useIPv6Address"); value.Exists() { data.LanFailoverIpv6Addr = types.BoolValue(value.Bool()) } else { - data.LanFailoverIpv6Addr = types.BoolNull() + data.LanFailoverIpv6Addr = types.BoolValue(false) } if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.name"); value.Exists() { data.LanFailoverInterfaceName = types.StringValue(value.String()) @@ -347,14 +347,14 @@ func (data *DeviceHAPair) fromBodyPartial(ctx context.Context, res gjson.Result) } else { data.LanFailoverName = types.StringNull() } - if value := res.Get("ftdHABootstrap.lanFailover.subnetMask"); value.Exists() && !data.LanFailoverSubnetMask.IsNull() { - data.LanFailoverSubnetMask = types.StringValue(value.String()) + if value := res.Get("ftdHABootstrap.lanFailover.subnetMask"); value.Exists() && !data.LanFailoverNetmask.IsNull() { + data.LanFailoverNetmask = types.StringValue(value.String()) } else { - data.LanFailoverSubnetMask = types.StringNull() + data.LanFailoverNetmask = types.StringNull() } if value := res.Get("ftdHABootstrap.lanFailover.useIPv6Address"); value.Exists() && !data.LanFailoverIpv6Addr.IsNull() { data.LanFailoverIpv6Addr = types.BoolValue(value.Bool()) - } else { + } else if data.LanFailoverIpv6Addr.ValueBool() != false { data.LanFailoverIpv6Addr = types.BoolNull() } if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.name"); value.Exists() && !data.LanFailoverInterfaceName.IsNull() { diff --git a/internal/provider/resource_fmc_device_ha_pair.go b/internal/provider/resource_fmc_device_ha_pair.go index 6ca82fb8..1fb3a136 100644 --- a/internal/provider/resource_fmc_device_ha_pair.go +++ b/internal/provider/resource_fmc_device_ha_pair.go @@ -29,6 +29,7 @@ import ( "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/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -81,7 +82,7 @@ func (r *DeviceHAPairResource) Schema(ctx context.Context, req resource.SchemaRe }, }, "name": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("The name of the access control policy.").String, + MarkdownDescription: helpers.NewAttributeDescription("The name of the High Availability Pair.").String, Required: true, }, "primary_device_id": schema.StringAttribute{ @@ -123,13 +124,15 @@ func (r *DeviceHAPairResource) Schema(ctx context.Context, req resource.SchemaRe MarkdownDescription: helpers.NewAttributeDescription("").String, Required: true, }, - "lan_failover_subnet_mask": schema.StringAttribute{ + "lan_failover_netmask": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("").String, Optional: true, }, "lan_failover_ipv6_addr": schema.BoolAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("").String, + MarkdownDescription: helpers.NewAttributeDescription("").AddDefaultValueDescription("false").String, Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, "lan_failover_interface_name": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("Name of physical interface").String, @@ -141,7 +144,7 @@ func (r *DeviceHAPairResource) Schema(ctx context.Context, req resource.SchemaRe }, "lan_failover_interface_type": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("Type of physical interface.").String, - Optional: true, + Required: true, }, "stateful_failover_standby_ip": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("").String, @@ -241,7 +244,7 @@ func (r *DeviceHAPairResource) Create(ctx context.Context, req resource.CreateRe resp.Diagnostics.AddError("Client Error", fmt.Sprintf("API task for the new device failed: %s, %s", task.Get("message"), task.Get("description"))) return } - if stat != "PENDING" && stat != "RUNNING" { + if stat != "PENDING" && stat != "RUNNING" && stat != "IN_PROGRESS" { break } time.Sleep(atom) @@ -364,8 +367,6 @@ func (r *DeviceHAPairResource) Update(ctx context.Context, req resource.UpdateRe // End of section. //template:end update -// Section below is generated&owned by "gen/generator.go". //template:begin delete - func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state DeviceHAPair @@ -393,8 +394,6 @@ func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRe resp.State.RemoveResource(ctx) } -// End of section. //template:end delete - // Section below is generated&owned by "gen/generator.go". //template:begin import func (r *DeviceHAPairResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/internal/provider/resource_fmc_device_ha_pair_test.go b/internal/provider/resource_fmc_device_ha_pair_test.go index d10de1d4..78cd5d2b 100644 --- a/internal/provider/resource_fmc_device_ha_pair_test.go +++ b/internal/provider/resource_fmc_device_ha_pair_test.go @@ -30,6 +30,9 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAcc func TestAccFmcDeviceHAPair(t *testing.T) { + if os.Getenv("TF_VAR_device_id") == "" && os.Getenv("TF_VAR_device_2_id") == "" { + t.Skip("skipping test, set environment variable TF_VAR_device_id or TF_VAR_device_2_id") + } var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "name", "FTD_HA")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "is_encryption_enabled", "false")) @@ -39,7 +42,7 @@ func TestAccFmcDeviceHAPair(t *testing.T) { checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_subnet_mask", "255.255.255.0")) + checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_netmask", "255.255.255.0")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) @@ -91,12 +94,13 @@ func testAccFmcDeviceHAPairConfig_minimum() string { config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" config += ` primary_device_id = var.device_id` + "\n" - config += ` secondary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_2_id` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" + config += ` lan_failover_interface_type = "PhysicalInterface"` + "\n" config += `}` + "\n" return config } @@ -109,7 +113,7 @@ func testAccFmcDeviceHAPairConfig_all() string { config := `resource "fmc_device_ha_pair" "test" {` + "\n" config += ` name = "FTD_HA"` + "\n" config += ` primary_device_id = var.device_id` + "\n" - config += ` secondary_device_id = var.device_id` + "\n" + config += ` secondary_device_id = var.device_2_id` + "\n" config += ` is_encryption_enabled = false` + "\n" config += ` use_same_link_for_failovers = false` + "\n" config += ` shared_key = "cisco123"` + "\n" @@ -117,7 +121,7 @@ func testAccFmcDeviceHAPairConfig_all() string { config += ` lan_failover_standby_ip = "1.1.1.2"` + "\n" config += ` lan_failover_active_ip = "1.1.1.1"` + "\n" config += ` lan_failover_name = "LAN-INTERFACE"` + "\n" - config += ` lan_failover_subnet_mask = "255.255.255.0"` + "\n" + config += ` lan_failover_netmask = "255.255.255.0"` + "\n" config += ` lan_failover_ipv6_addr = false` + "\n" config += ` lan_failover_interface_name = "GigabitEthernet0/0"` + "\n" config += ` lan_failover_interface_id = "757kdgh5-41c4-4558-a4d0-a8c07ac08470"` + "\n" From ca01ffe98ef508e27fa21ff4073fbc2709a26717 Mon Sep 17 00:00:00 2001 From: kadadhic Date: Tue, 10 Dec 2024 12:35:00 +0530 Subject: [PATCH 4/6] added support for ha break in delete --- docs/data-sources/device_ha_pair.md | 2 +- docs/resources/device_ha_pair.md | 4 ++-- gen/definitions/device_ha_pair.yaml | 4 ++-- .../data_source_fmc_device_ha_pair.go | 2 +- internal/provider/model_fmc_device_ha_pair.go | 12 ++++++++++++ .../provider/resource_fmc_device_ha_pair.go | 19 +++++++++++++------ 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/data-sources/device_ha_pair.md b/docs/data-sources/device_ha_pair.md index 25eb04cf..149f2a73 100644 --- a/docs/data-sources/device_ha_pair.md +++ b/docs/data-sources/device_ha_pair.md @@ -31,7 +31,7 @@ data "fmc_device_ha_pair" "example" { ### Read-Only -- `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. +- `action` (String) FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy - `enc_key_generation_scheme` (String) Select the encyption key generation scheme. - `force_break` (Boolean) FTD HA Force Break option (PUT Option). - `is_encryption_enabled` (Boolean) Boolean field to enable encryption diff --git a/docs/resources/device_ha_pair.md b/docs/resources/device_ha_pair.md index 9b951dda..f1f5fee8 100644 --- a/docs/resources/device_ha_pair.md +++ b/docs/resources/device_ha_pair.md @@ -59,8 +59,8 @@ resource "fmc_device_ha_pair" "example" { ### Optional -- `action` (String) FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. - - Choices: `SWITCH`, `HABREAK` +- `action` (String) FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy + - Choices: `SWITCH` - `domain` (String) The name of the FMC domain - `enc_key_generation_scheme` (String) Select the encyption key generation scheme. - Choices: `AUTO`, `CUSTOM` diff --git a/gen/definitions/device_ha_pair.yaml b/gen/definitions/device_ha_pair.yaml index e95f7355..b809b7e4 100644 --- a/gen/definitions/device_ha_pair.yaml +++ b/gen/definitions/device_ha_pair.yaml @@ -146,8 +146,8 @@ attributes: example: PhysicalInterface - model_name: action type: String - description: FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch. - enum_values: [ SWITCH, HABREAK ] + description: FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy + enum_values: [ SWITCH ] exclude_test: true example: SWITCH - model_name: forceBreak diff --git a/internal/provider/data_source_fmc_device_ha_pair.go b/internal/provider/data_source_fmc_device_ha_pair.go index 1cf3f457..008b9f8d 100644 --- a/internal/provider/data_source_fmc_device_ha_pair.go +++ b/internal/provider/data_source_fmc_device_ha_pair.go @@ -166,7 +166,7 @@ func (d *DeviceHAPairDataSource) Schema(ctx context.Context, req datasource.Sche Computed: true, }, "action": schema.StringAttribute{ - MarkdownDescription: "FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch.", + MarkdownDescription: "FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy", Computed: true, }, "force_break": schema.BoolAttribute{ diff --git a/internal/provider/model_fmc_device_ha_pair.go b/internal/provider/model_fmc_device_ha_pair.go index 02347cf1..a83eab56 100644 --- a/internal/provider/model_fmc_device_ha_pair.go +++ b/internal/provider/model_fmc_device_ha_pair.go @@ -442,3 +442,15 @@ func (data *DeviceHAPair) fromBodyUnknowns(ctx context.Context, res gjson.Result // Section below is generated&owned by "gen/generator.go". //template:begin toBodyNonBulk // End of section. //template:end toBodyNonBulk + +// toBodyPutDelete generates minimal required body to brek the HA. +func (data DeviceHAPair) toBodyPutDelete(ctx context.Context, state DeviceHAPair) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + + body, _ = sjson.Set(body, "action", "HABREAK") + body, _ = sjson.Set(body, "forceBreak", true) + return body +} diff --git a/internal/provider/resource_fmc_device_ha_pair.go b/internal/provider/resource_fmc_device_ha_pair.go index 1fb3a136..fcbe4349 100644 --- a/internal/provider/resource_fmc_device_ha_pair.go +++ b/internal/provider/resource_fmc_device_ha_pair.go @@ -179,10 +179,10 @@ func (r *DeviceHAPairResource) Schema(ctx context.Context, req resource.SchemaRe Optional: true, }, "action": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("FTD HA PUT operation action. Specifically used for breaking FTD HA or manual switch.").AddStringEnumDescription("SWITCH", "HABREAK").String, + MarkdownDescription: helpers.NewAttributeDescription("FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy").AddStringEnumDescription("SWITCH").String, Optional: true, Validators: []validator.String{ - stringvalidator.OneOf("SWITCH", "HABREAK"), + stringvalidator.OneOf("SWITCH"), }, }, "force_break": schema.BoolAttribute{ @@ -381,13 +381,20 @@ func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRe 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...) + // Start of HA Break code + body := state.toBodyPutDelete(ctx, DeviceHAPair{}) + 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 delete object (DELETE), got error: %s, %s", err, res.String())) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to remove object configuration phase 1 (PUT), got error: %s, %s", err, res.String())) return } + // End of HA Break code + // tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Break", 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 Break HA, got error: %s, %s", err, res.String())) + // return + // } tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString())) From f9f2ebd1075236a5eba670d794dbcf3b4a716a0a Mon Sep 17 00:00:00 2001 From: kadadhic Date: Tue, 10 Dec 2024 13:35:12 +0530 Subject: [PATCH 5/6] fixed update issues --- docs/data-sources/device_ha_pair.md | 1 - docs/resources/device_ha_pair.md | 2 - .../resources/fmc_device_ha_pair/resource.tf | 1 - gen/definitions/device_ha_pair.yaml | 9 ++- .../data_source_fmc_device_ha_pair.go | 4 -- .../data_source_fmc_device_ha_pair_test.go | 4 -- internal/provider/model_fmc_device_ha_pair.go | 67 ++++--------------- .../provider/resource_fmc_device_ha_pair.go | 10 +-- .../resource_fmc_device_ha_pair_test.go | 4 -- 9 files changed, 18 insertions(+), 84 deletions(-) diff --git a/docs/data-sources/device_ha_pair.md b/docs/data-sources/device_ha_pair.md index 149f2a73..69df232b 100644 --- a/docs/data-sources/device_ha_pair.md +++ b/docs/data-sources/device_ha_pair.md @@ -33,7 +33,6 @@ data "fmc_device_ha_pair" "example" { - `action` (String) FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy - `enc_key_generation_scheme` (String) Select the encyption key generation scheme. -- `force_break` (Boolean) FTD HA Force Break option (PUT Option). - `is_encryption_enabled` (Boolean) Boolean field to enable encryption - `lan_failover_active_ip` (String) - `lan_failover_interface_id` (String) ID of physical interface. diff --git a/docs/resources/device_ha_pair.md b/docs/resources/device_ha_pair.md index f1f5fee8..abb7dfbb 100644 --- a/docs/resources/device_ha_pair.md +++ b/docs/resources/device_ha_pair.md @@ -38,7 +38,6 @@ resource "fmc_device_ha_pair" "example" { stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470" stateful_failover_interface_type = "PhysicalInterface" action = "SWITCH" - force_break = false } ``` @@ -64,7 +63,6 @@ resource "fmc_device_ha_pair" "example" { - `domain` (String) The name of the FMC domain - `enc_key_generation_scheme` (String) Select the encyption key generation scheme. - Choices: `AUTO`, `CUSTOM` -- `force_break` (Boolean) FTD HA Force Break option (PUT Option). - `is_encryption_enabled` (Boolean) Boolean field to enable encryption - `lan_failover_interface_name` (String) Name of physical interface - `lan_failover_ipv6_addr` (Boolean) - Default value: `false` diff --git a/examples/resources/fmc_device_ha_pair/resource.tf b/examples/resources/fmc_device_ha_pair/resource.tf index 6387e239..372ff604 100644 --- a/examples/resources/fmc_device_ha_pair/resource.tf +++ b/examples/resources/fmc_device_ha_pair/resource.tf @@ -23,5 +23,4 @@ resource "fmc_device_ha_pair" "example" { stateful_failover_interface_id = "76d24097-hj7r-7786-a4d0-a8c07ac08470" stateful_failover_interface_type = "PhysicalInterface" action = "SWITCH" - force_break = false } diff --git a/gen/definitions/device_ha_pair.yaml b/gen/definitions/device_ha_pair.yaml index b809b7e4..56f441a3 100644 --- a/gen/definitions/device_ha_pair.yaml +++ b/gen/definitions/device_ha_pair.yaml @@ -38,6 +38,7 @@ attributes: - model_name: useSameLinkForFailovers type: Bool mandatory: true + write_only: true data_path: [ftdHABootstrap] example: false description: Boolean field to enable same link for failovers @@ -49,6 +50,7 @@ attributes: - model_name: encKeyGenerationScheme type: String data_path: [ftdHABootstrap] + write_only: true description: Select the encyption key generation scheme. example: "CUSTOM" enum_values: [ AUTO, CUSTOM ] @@ -92,6 +94,7 @@ attributes: mandatory: true tf_name: lan_failover_interface_id data_path: [ftdHABootstrap,lanFailover,interfaceObject] + write_only: true description: ID of physical interface. example: 757kdgh5-41c4-4558-a4d0-a8c07ac08470 - model_name: type @@ -99,6 +102,7 @@ attributes: mandatory: true tf_name: lan_failover_interface_type data_path: [ftdHABootstrap,lanFailover,interfaceObject] + write_only: true description: Type of physical interface. example: PhysicalInterface - model_name: standbyIP @@ -150,10 +154,5 @@ attributes: enum_values: [ SWITCH ] exclude_test: true example: SWITCH - - model_name: forceBreak - type: Bool - description: FTD HA Force Break option (PUT Option). - exclude_test: true - example: false test_prerequisites: |- variable "device_id" { default = null } // tests will set $TF_VAR_device_id \ No newline at end of file diff --git a/internal/provider/data_source_fmc_device_ha_pair.go b/internal/provider/data_source_fmc_device_ha_pair.go index 008b9f8d..71788b2e 100644 --- a/internal/provider/data_source_fmc_device_ha_pair.go +++ b/internal/provider/data_source_fmc_device_ha_pair.go @@ -169,10 +169,6 @@ func (d *DeviceHAPairDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "FTD HA PUT operation action. Specifically used for manual switch. HA Break will be triggered when you run terraform destroy", Computed: true, }, - "force_break": schema.BoolAttribute{ - MarkdownDescription: "FTD HA Force Break option (PUT Option).", - Computed: true, - }, }, } } diff --git a/internal/provider/data_source_fmc_device_ha_pair_test.go b/internal/provider/data_source_fmc_device_ha_pair_test.go index 489b7079..b9795ee5 100644 --- a/internal/provider/data_source_fmc_device_ha_pair_test.go +++ b/internal/provider/data_source_fmc_device_ha_pair_test.go @@ -36,17 +36,13 @@ func TestAccDataSourceFmcDeviceHAPair(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "name", "FTD_HA")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "is_encryption_enabled", "false")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "use_same_link_for_failovers", "false")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "shared_key", "cisco123")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "enc_key_generation_scheme", "CUSTOM")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_netmask", "255.255.255.0")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) - checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "lan_failover_interface_type", "PhysicalInterface")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_standby_ip", "10.10.10.2")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_active_ip", "10.10.10.1")) checks = append(checks, resource.TestCheckResourceAttr("data.fmc_device_ha_pair.test", "stateful_failover_name", "Stateful-INTERFACE")) diff --git a/internal/provider/model_fmc_device_ha_pair.go b/internal/provider/model_fmc_device_ha_pair.go index a83eab56..76386ae3 100644 --- a/internal/provider/model_fmc_device_ha_pair.go +++ b/internal/provider/model_fmc_device_ha_pair.go @@ -57,7 +57,6 @@ type DeviceHAPair struct { StatefulFailoverInterfaceId types.String `tfsdk:"stateful_failover_interface_id"` StatefulFailoverInterfaceType types.String `tfsdk:"stateful_failover_interface_type"` Action types.String `tfsdk:"action"` - ForceBreak types.Bool `tfsdk:"force_break"` } // End of section. //template:end types @@ -150,9 +149,6 @@ func (data DeviceHAPair) toBody(ctx context.Context, state DeviceHAPair) string if !data.Action.IsNull() { body, _ = sjson.Set(body, "action", data.Action.ValueString()) } - if !data.ForceBreak.IsNull() { - body, _ = sjson.Set(body, "forceBreak", data.ForceBreak.ValueBool()) - } return body } @@ -181,21 +177,11 @@ func (data *DeviceHAPair) fromBody(ctx context.Context, res gjson.Result) { } else { data.IsEncryptionEnabled = types.BoolNull() } - if value := res.Get("ftdHABootstrap.useSameLinkForFailovers"); value.Exists() { - data.UseSameLinkForFailovers = types.BoolValue(value.Bool()) - } else { - data.UseSameLinkForFailovers = types.BoolNull() - } if value := res.Get("ftdHABootstrap.sharedKey"); value.Exists() { data.SharedKey = types.StringValue(value.String()) } else { data.SharedKey = types.StringNull() } - if value := res.Get("ftdHABootstrap.encKeyGenerationScheme"); value.Exists() { - data.EncKeyGenerationScheme = types.StringValue(value.String()) - } else { - data.EncKeyGenerationScheme = types.StringNull() - } if value := res.Get("ftdHABootstrap.lanFailover.standbyIP"); value.Exists() { data.LanFailoverStandbyIp = types.StringValue(value.String()) } else { @@ -226,16 +212,6 @@ func (data *DeviceHAPair) fromBody(ctx context.Context, res gjson.Result) { } else { data.LanFailoverInterfaceName = types.StringNull() } - if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.id"); value.Exists() { - data.LanFailoverInterfaceId = types.StringValue(value.String()) - } else { - data.LanFailoverInterfaceId = types.StringNull() - } - if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.type"); value.Exists() { - data.LanFailoverInterfaceType = types.StringValue(value.String()) - } else { - data.LanFailoverInterfaceType = types.StringNull() - } if value := res.Get("ftdHABootstrap.statefulFailover.standbyIP"); value.Exists() { data.StatefulFailoverStandbyIp = types.StringValue(value.String()) } else { @@ -281,11 +257,6 @@ func (data *DeviceHAPair) fromBody(ctx context.Context, res gjson.Result) { } else { data.Action = types.StringNull() } - if value := res.Get("forceBreak"); value.Exists() { - data.ForceBreak = types.BoolValue(value.Bool()) - } else { - data.ForceBreak = types.BoolNull() - } } // End of section. //template:end fromBody @@ -317,21 +288,11 @@ func (data *DeviceHAPair) fromBodyPartial(ctx context.Context, res gjson.Result) } else { data.IsEncryptionEnabled = types.BoolNull() } - if value := res.Get("ftdHABootstrap.useSameLinkForFailovers"); value.Exists() && !data.UseSameLinkForFailovers.IsNull() { - data.UseSameLinkForFailovers = types.BoolValue(value.Bool()) - } else { - data.UseSameLinkForFailovers = types.BoolNull() - } if value := res.Get("ftdHABootstrap.sharedKey"); value.Exists() && !data.SharedKey.IsNull() { data.SharedKey = types.StringValue(value.String()) } else { data.SharedKey = types.StringNull() } - if value := res.Get("ftdHABootstrap.encKeyGenerationScheme"); value.Exists() && !data.EncKeyGenerationScheme.IsNull() { - data.EncKeyGenerationScheme = types.StringValue(value.String()) - } else { - data.EncKeyGenerationScheme = types.StringNull() - } if value := res.Get("ftdHABootstrap.lanFailover.standbyIP"); value.Exists() && !data.LanFailoverStandbyIp.IsNull() { data.LanFailoverStandbyIp = types.StringValue(value.String()) } else { @@ -362,16 +323,6 @@ func (data *DeviceHAPair) fromBodyPartial(ctx context.Context, res gjson.Result) } else { data.LanFailoverInterfaceName = types.StringNull() } - if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.id"); value.Exists() && !data.LanFailoverInterfaceId.IsNull() { - data.LanFailoverInterfaceId = types.StringValue(value.String()) - } else { - data.LanFailoverInterfaceId = types.StringNull() - } - if value := res.Get("ftdHABootstrap.lanFailover.interfaceObject.type"); value.Exists() && !data.LanFailoverInterfaceType.IsNull() { - data.LanFailoverInterfaceType = types.StringValue(value.String()) - } else { - data.LanFailoverInterfaceType = types.StringNull() - } if value := res.Get("ftdHABootstrap.statefulFailover.standbyIP"); value.Exists() && !data.StatefulFailoverStandbyIp.IsNull() { data.StatefulFailoverStandbyIp = types.StringValue(value.String()) } else { @@ -417,11 +368,6 @@ func (data *DeviceHAPair) fromBodyPartial(ctx context.Context, res gjson.Result) } else { data.Action = types.StringNull() } - if value := res.Get("forceBreak"); value.Exists() && !data.ForceBreak.IsNull() { - data.ForceBreak = types.BoolValue(value.Bool()) - } else { - data.ForceBreak = types.BoolNull() - } } // End of section. //template:end fromBodyPartial @@ -454,3 +400,16 @@ func (data DeviceHAPair) toBodyPutDelete(ctx context.Context, state DeviceHAPair body, _ = sjson.Set(body, "forceBreak", true) return body } +func (data DeviceHAPair) toBodyPutUpdate(ctx context.Context, state DeviceHAPair) string { + body := "" + if data.Id.ValueString() != "" { + body, _ = sjson.Set(body, "id", data.Id.ValueString()) + } + if data.Name.ValueString() != "" { + body, _ = sjson.Set(body, "name", data.Name.ValueString()) + } + if data.Action.ValueString() == "SWITCH" { + body, _ = sjson.Set(body, "action", "SWITCH") + } + return body +} diff --git a/internal/provider/resource_fmc_device_ha_pair.go b/internal/provider/resource_fmc_device_ha_pair.go index fcbe4349..9666b5c3 100644 --- a/internal/provider/resource_fmc_device_ha_pair.go +++ b/internal/provider/resource_fmc_device_ha_pair.go @@ -185,10 +185,6 @@ func (r *DeviceHAPairResource) Schema(ctx context.Context, req resource.SchemaRe stringvalidator.OneOf("SWITCH"), }, }, - "force_break": schema.BoolAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("FTD HA Force Break option (PUT Option).").String, - Optional: true, - }, }, } } @@ -327,8 +323,6 @@ func (r *DeviceHAPairResource) Read(ctx context.Context, req resource.ReadReques // End of section. //template:end read -// Section below is generated&owned by "gen/generator.go". //template:begin update - func (r *DeviceHAPairResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan, state DeviceHAPair @@ -352,7 +346,7 @@ func (r *DeviceHAPairResource) Update(ctx context.Context, req resource.UpdateRe tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) - body := plan.toBody(ctx, state) + body := plan.toBodyPutUpdate(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())) @@ -365,8 +359,6 @@ func (r *DeviceHAPairResource) Update(ctx context.Context, req resource.UpdateRe resp.Diagnostics.Append(diags...) } -// End of section. //template:end update - func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state DeviceHAPair diff --git a/internal/provider/resource_fmc_device_ha_pair_test.go b/internal/provider/resource_fmc_device_ha_pair_test.go index 78cd5d2b..11864b3e 100644 --- a/internal/provider/resource_fmc_device_ha_pair_test.go +++ b/internal/provider/resource_fmc_device_ha_pair_test.go @@ -36,17 +36,13 @@ func TestAccFmcDeviceHAPair(t *testing.T) { var checks []resource.TestCheckFunc checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "name", "FTD_HA")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "is_encryption_enabled", "false")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "use_same_link_for_failovers", "false")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "shared_key", "cisco123")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "enc_key_generation_scheme", "CUSTOM")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_standby_ip", "1.1.1.2")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_active_ip", "1.1.1.1")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_name", "LAN-INTERFACE")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_netmask", "255.255.255.0")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_ipv6_addr", "false")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_name", "GigabitEthernet0/0")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_id", "757kdgh5-41c4-4558-a4d0-a8c07ac08470")) - checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "lan_failover_interface_type", "PhysicalInterface")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_standby_ip", "10.10.10.2")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_active_ip", "10.10.10.1")) checks = append(checks, resource.TestCheckResourceAttr("fmc_device_ha_pair.test", "stateful_failover_name", "Stateful-INTERFACE")) From 3048ea1002596081d2a4e90feed12614c07915e7 Mon Sep 17 00:00:00 2001 From: kadadhic Date: Tue, 10 Dec 2024 14:05:12 +0530 Subject: [PATCH 6/6] improved the destroy logic by adding appropriate wait --- .../provider/resource_fmc_device_ha_pair.go | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/internal/provider/resource_fmc_device_ha_pair.go b/internal/provider/resource_fmc_device_ha_pair.go index 9666b5c3..b48991d3 100644 --- a/internal/provider/resource_fmc_device_ha_pair.go +++ b/internal/provider/resource_fmc_device_ha_pair.go @@ -381,13 +381,29 @@ func (r *DeviceHAPairResource) Delete(ctx context.Context, req resource.DeleteRe return } // End of HA Break code - // tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Break", 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 Break HA, got error: %s, %s", err, res.String())) - // return - // } + // Adding code to poll object + taskID := res.Get("metadata.task.id").String() + tflog.Debug(ctx, fmt.Sprintf("%s: Async task initiated successfully", taskID)) + + const atom time.Duration = 5 * time.Second + // We need device's UUID, but it only shows after the task succeeds. Poll the task. + for i := time.Duration(0); i < 5*time.Minute; i += atom { + task, err := r.client.Get("/api/fmc_config/v1/domain/{DOMAIN_UUID}/job/taskstatuses/"+url.QueryEscape(taskID), reqMods...) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to read object (GET), got error: %s, %s", err, task.String())) + return + } + stat := strings.ToUpper(task.Get("status").String()) + if stat == "FAILED" { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("API task for the new device failed: %s, %s", task.Get("message"), task.Get("description"))) + return + } + if stat != "PENDING" && stat != "RUNNING" && stat != "IN_PROGRESS" { + break + } + time.Sleep(atom) + } tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString())) resp.State.RemoveResource(ctx)