Skip to content

Commit

Permalink
fix(LH-72256): Ordering Issues (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
weilueluo authored Oct 23, 2023
1 parent b10a0a6 commit 737ff56
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 121 deletions.
34 changes: 34 additions & 0 deletions docs/data-sources/ftd_device.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "cdo_ftd_device Data Source - cdo"
subcategory: ""
description: |-
Ftd data source
---

# cdo_ftd_device (Data Source)

Ftd data source



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) A human-readable name for the Firewall Threat Defense (FTD). This name must be unique.

### Read-Only

- `access_policy_id` (String) The ID of the cloud-delivered FMC (cdFMC) access policy applied to this FTD.
- `access_policy_name` (String) The name of the Cloud-Delivered FMC (cdFMC) access policy that will be used by the FTD.
- `generated_command` (String) The command to run in the FTD CLI to register it with the cloud-delivered FMC (cdFMC).
- `hostname` (String) The Hostname of the cloud-delivered FMC (cdFMC) manages this FTD.
- `id` (String) Unique identifier of the device. This is a UUID and is automatically generated when the device is created.
- `labels` (List of String) Set a list of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.
- `licenses` (List of String) Comma-separated list of licenses to apply to this FTD. You must enable at least the "BASE" license. Allowed values are: ["BASE", "CARRIER", "THREAT", "MALWARE", "URLFilter",].
- `nat_id` (String) The Network Address Translation (NAT) ID of this FTD.
- `performance_tier` (String) The performance tier of the virtual FTD, if virtual is set to false, this field is ignored as performance tiers are not applicable to physical FTD devices. Allowed values are: ["FTDv5", "FTDv10", "FTDv20", "FTDv30", "FTDv50", "FTDv100", "FTDv"].
- `reg_key` (String) The Registration Key of this FTD.
- `virtual` (Boolean) This determines if this FTD is virtual. If false, performance_tier is ignored as performance tiers are not applicable to physical FTD devices.
2 changes: 1 addition & 1 deletion docs/resources/asa_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Provides an ASA device resource. This allows ASA devices to be onboarded, update
### Optional

- `connector_name` (String) The name of the Secure Device Connector (SDC) that will be used to communicate with the device. This value is not required if the connector type selected is Cloud Connector (CDG).
- `labels` (List of String) Set a list of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.
- `labels` (Set of String) Specify a set of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.

### Read-Only

Expand Down
4 changes: 2 additions & 2 deletions docs/resources/ftd_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ Provides a Firewall Threat Defense device resource. Use this to onboard, update,
### Required

- `access_policy_name` (String) The name of the Cloud-Delivered FMC (cdFMC) access policy that will be used by the FTD.
- `licenses` (List of String) Comma-separated list of licenses to apply to this FTD. You must enable at least the "BASE" license. Allowed values are: ["BASE", "CARRIER", "THREAT", "MALWARE", "URLFilter",].
- `licenses` (Set of String) Comma-separated list of licenses to apply to this FTD. You must enable at least the "BASE" license. Allowed values are: ["BASE", "CARRIER", "THREAT", "MALWARE", "URLFilter",].
- `name` (String) A human-readable name for the Firewall Threat Defense (FTD). This name must be unique.
- `virtual` (Boolean) This determines if this FTD is virtual. If false, performance_tier is ignored as performance tiers are not applicable to physical FTD devices.

### Optional

- `labels` (List of String) Set a list of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.
- `labels` (Set of String) Specify a set of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.
- `performance_tier` (String) The performance tier of the virtual FTD, if virtual is set to false, this field is ignored as performance tiers are not applicable to physical FTD devices. Allowed values are: ["FTDv5", "FTDv10", "FTDv20", "FTDv30", "FTDv50", "FTDv100", "FTDv"].

### Read-Only
Expand Down
2 changes: 1 addition & 1 deletion docs/resources/ios_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Provides an iOS device resource. This allows iOS devices to be onboarded, update

### Optional

- `labels` (List of String) Set a list of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.
- `labels` (Set of String) Specify a set of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.

### Read-Only

Expand Down
62 changes: 28 additions & 34 deletions provider/internal/device/asa/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ package asa
import (
"context"
"fmt"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/device/tags"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/util"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/util/sliceutil"
"github.com/CiscoDevnet/terraform-provider-cdo/planmodifiers"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault"
"strconv"
"strings"

Expand Down Expand Up @@ -44,14 +40,14 @@ type AsaDeviceResource struct {
}

type AsaDeviceResourceModel struct {
ID types.String `tfsdk:"id"`
ConnectorType types.String `tfsdk:"connector_type"`
ConnectorName types.String `tfsdk:"connector_name"`
Name types.String `tfsdk:"name"`
SocketAddress types.String `tfsdk:"socket_address"`
Host types.String `tfsdk:"host"`
Port types.Int64 `tfsdk:"port"`
Labels []types.String `tfsdk:"labels"`
ID types.String `tfsdk:"id"`
ConnectorType types.String `tfsdk:"connector_type"`
ConnectorName types.String `tfsdk:"connector_name"`
Name types.String `tfsdk:"name"`
SocketAddress types.String `tfsdk:"socket_address"`
Host types.String `tfsdk:"host"`
Port types.Int64 `tfsdk:"port"`
Labels types.Set `tfsdk:"labels"`

Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
Expand Down Expand Up @@ -117,18 +113,12 @@ func (r *AsaDeviceResource) Schema(ctx context.Context, req resource.SchemaReque
stringplanmodifier.UseStateForUnknown(),
},
},
"labels": schema.ListAttribute{ // TODO: use set when we go to 1.0.0, https://jira-eng-rtp3.cisco.com/jira/browse/LH-71968
MarkdownDescription: "Set a list of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.",
"labels": schema.SetAttribute{
MarkdownDescription: "Specify a set of labels to identify the device as part of a group. Refer to the [CDO documentation](https://docs.defenseorchestrator.com/t-applying-labels-to-devices-and-objects.html#!c-labels-and-filtering.html) for details on how labels are used in CDO.",
Optional: true,
Computed: true,
ElementType: types.StringType,
Default: listdefault.StaticValue(types.ListValueMust(types.StringType, []attr.Value{})), // default to empty list
Validators: []validator.List{
listvalidator.UniqueValues(),
},
PlanModifiers: []planmodifier.List{
planmodifiers.UseStateForUnorderedStringList(),
},
Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), // default to empty list
},
"username": schema.StringAttribute{
MarkdownDescription: "The username used to authenticate with the device.",
Expand Down Expand Up @@ -206,10 +196,7 @@ func (r *AsaDeviceResource) Read(ctx context.Context, req resource.ReadRequest,
stateData.SocketAddress = types.StringValue(asaReadOutp.SocketAddress)
stateData.Host = types.StringValue(asaReadOutp.Host)
stateData.IgnoreCertificate = types.BoolValue(asaReadOutp.IgnoreCertificate)
// only set labels if it is different
if !sliceutil.StringsEqualUnordered(util.TFStringListToGoStringList(stateData.Labels), asaReadOutp.Tags.Labels) {
stateData.Labels = util.GoStringSliceToTFStringList(asaReadOutp.Tags.Labels)
}
stateData.Labels = util.GoStringSliceToTFStringSet(asaReadOutp.Tags.Labels)

tflog.Trace(ctx, "done read ASA device resource")

Expand Down Expand Up @@ -244,7 +231,12 @@ func (r *AsaDeviceResource) Create(ctx context.Context, req resource.CreateReque
specificSdcOutp = &connector.ReadOutput{}
}

tagsInp := tags.New(util.TFStringListToGoStringList(planData.Labels)...)
// convert tf tags to go tags
planTags, err := util.TFStringSetToTagLabels(ctx, planData.Labels)
if err != nil {
res.Diagnostics.AddError("error while converting terraform tags to go tags", err.Error())
return
}

createInp := asa.NewCreateRequestInput(
planData.Name.ValueString(),
Expand All @@ -254,7 +246,7 @@ func (r *AsaDeviceResource) Create(ctx context.Context, req resource.CreateReque
planData.Username.ValueString(),
planData.Password.ValueString(),
planData.IgnoreCertificate.ValueBool(),
tagsInp,
planTags,
)

createOutp, createErr := r.client.CreateAsa(ctx, *createInp)
Expand Down Expand Up @@ -305,14 +297,19 @@ func (r *AsaDeviceResource) Update(ctx context.Context, req resource.UpdateReque
return
}

tagsInp := tags.New(util.TFStringListToGoStringList(planData.Labels)...)
// convert tf tags to go tags
planTags, err := util.TFStringSetToTagLabels(ctx, planData.Labels)
if err != nil {
res.Diagnostics.AddError("error while converting terraform tags to go tags", err.Error())
return
}

updateInp := asa.NewUpdateInput(
stateData.ID.ValueString(),
stateData.Name.ValueString(),
"",
"",
tagsInp,
planTags,
)

if isNameUpdated(planData, stateData) {
Expand Down Expand Up @@ -354,10 +351,7 @@ func (r *AsaDeviceResource) Update(ctx context.Context, req resource.UpdateReque
stateData.SocketAddress = planData.SocketAddress
stateData.Host = types.StringValue(updateOutp.Host)
stateData.Port = types.Int64Value(port)
// only set labels if it is different
if !sliceutil.StringsEqualUnordered(util.TFStringListToGoStringList(stateData.Labels), updateOutp.Tags.Labels) {
stateData.Labels = planData.Labels
}
stateData.Labels = planData.Labels

stateData.IgnoreCertificate = planData.IgnoreCertificate

Expand Down
42 changes: 24 additions & 18 deletions provider/internal/device/ftd/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import (
"strings"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/cloudftd"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/device/tags"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/ftd/license"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/ftd/tier"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/util"
"github.com/CiscoDevnet/terraform-provider-cdo/internal/util/sliceutil"
"github.com/hashicorp/terraform-plugin-framework/types"
)

Expand Down Expand Up @@ -53,19 +51,15 @@ func Read(ctx context.Context, resource *Resource, stateData *ResourceModel) err
stateData.AccessPolicyName = types.StringValue(res.Metadata.AccessPolicyName)
stateData.AccessPolicyUid = types.StringValue(res.Metadata.AccessPolicyUid)
stateData.Virtual = types.BoolValue(res.Metadata.PerformanceTier != nil)
stateData.Licenses = util.GoStringSliceToTFStringList(license.ReplaceFmcLicenseTermsWithCdoTerms(strings.Split(res.Metadata.LicenseCaps, ",")))
stateData.Licenses = util.GoStringSliceToTFStringSet(license.ReplaceFmcLicenseTermsWithCdoTerms(strings.Split(res.Metadata.LicenseCaps, ",")))
if res.Metadata.PerformanceTier != nil { // nil means physical cloudftd
stateData.PerformanceTier = types.StringValue(string(*res.Metadata.PerformanceTier))
}
stateData.GeneratedCommand = types.StringValue(res.Metadata.GeneratedCommand)
stateData.Hostname = types.StringValue(res.Metadata.CloudManagerDomain)
stateData.NatId = types.StringValue(res.Metadata.NatID)
stateData.RegKey = types.StringValue(res.Metadata.RegKey)

// only set labels if it is different
if !sliceutil.StringsEqualUnordered(util.TFStringListToGoStringList(stateData.Labels), res.Tags.Labels) {
stateData.Labels = util.GoStringSliceToTFStringList(res.Tags.Labels)
}
stateData.Labels = util.GoStringSliceToTFStringSet(res.Tags.Labels)

return nil
}
Expand All @@ -82,10 +76,17 @@ func Create(ctx context.Context, resource *Resource, planData *ResourceModel) er
}
}

licensesGoList := util.TFStringListToGoStringList(planData.Licenses)
licenses, err := license.DeserializeAllFromCdo(strings.Join(licensesGoList, ","))
// convert tf licenses to go license
licenses, err := util.TFStringSetToLicenses(ctx, planData.Licenses)
if err != nil {
return err
}

tagsGoList := tags.New(util.TFStringListToGoStringList(planData.Labels)...)
// convert tf tags to go tags
planTags, err := util.TFStringSetToTagLabels(ctx, planData.Labels)
if err != nil {
return err
}

if err != nil {
return err
Expand All @@ -96,7 +97,7 @@ func Create(ctx context.Context, resource *Resource, planData *ResourceModel) er
performanceTier,
planData.Virtual.ValueBool(),
&licenses,
tagsGoList,
planTags,
)
res, err := resource.client.CreateCloudFtd(ctx, createInp)
if err != nil {
Expand All @@ -108,7 +109,8 @@ func Create(ctx context.Context, resource *Resource, planData *ResourceModel) er
planData.Name = types.StringValue(res.Name)
planData.AccessPolicyName = types.StringValue(res.Metadata.AccessPolicyName)
planData.AccessPolicyUid = types.StringValue(res.Metadata.AccessPolicyUid)
planData.Licenses = util.GoStringSliceToTFStringList(strings.Split(res.Metadata.LicenseCaps, ","))
planData.Licenses = util.GoStringSliceToTFStringSet(strings.Split(res.Metadata.LicenseCaps, ","))
planData.Labels = util.GoStringSliceToTFStringSet(res.Tags.Labels)
if res.Metadata.PerformanceTier != nil { // nil means physical cloud ftd
planData.PerformanceTier = types.StringValue(string(*res.Metadata.PerformanceTier))
}
Expand All @@ -123,10 +125,17 @@ func Create(ctx context.Context, resource *Resource, planData *ResourceModel) er
func Update(ctx context.Context, resource *Resource, planData *ResourceModel, stateData *ResourceModel) error {

// do update

// convert tf tags to go tags
planTags, err := util.TFStringSetToTagLabels(ctx, planData.Labels)
if err != nil {
return err
}

inp := cloudftd.NewUpdateInput(
planData.ID.ValueString(),
planData.Name.ValueString(),
tags.New(util.TFStringListToGoStringList(planData.Labels)...),
planTags,
)
res, err := resource.client.UpdateCloudFtd(ctx, inp)
if err != nil {
Expand All @@ -135,10 +144,7 @@ func Update(ctx context.Context, resource *Resource, planData *ResourceModel, st

// map return struct to model
stateData.Name = types.StringValue(res.Name)
// only set labels if it is different
if !sliceutil.StringsEqualUnordered(util.TFStringListToGoStringList(stateData.Labels), res.Tags.Labels) {
stateData.Labels = planData.Labels
}
stateData.Labels = planData.Labels

return nil
}
Expand Down
Loading

0 comments on commit 737ff56

Please sign in to comment.