diff --git a/docs/data-sources/device_acl_policy_definition.md b/docs/data-sources/device_acl_policy_definition.md index 3968478a..6d81a2e7 100644 --- a/docs/data-sources/device_acl_policy_definition.md +++ b/docs/data-sources/device_acl_policy_definition.md @@ -3,12 +3,12 @@ page_title: "sdwan_device_acl_policy_definition Data Source - terraform-provider-sdwan" subcategory: "Localized Policies" description: |- - This data source can read the Device ACL policy definition. + This data source can read the Device ACL Policy Definition . --- # sdwan_device_acl_policy_definition (Data Source) -This data source can read the Device ACL policy definition. +This data source can read the Device ACL Policy Definition . ## Example Usage @@ -23,7 +23,7 @@ data "sdwan_device_acl_policy_definition" "example" { ### Required -- `id` (String) The id of the policy definition +- `id` (String) The id of the object ### Read-Only @@ -31,8 +31,7 @@ data "sdwan_device_acl_policy_definition" "example" { - `description` (String) The description of the policy definition - `name` (String) The name of the policy definition - `sequences` (Attributes List) List of ACL sequences (see [below for nested schema](#nestedatt--sequences)) -- `type` (String) The policy definition type -- `version` (Number) The version of the policy definition +- `version` (Number) The version of the object ### Nested Schema for `sequences` diff --git a/docs/resources/device_acl_policy_definition.md b/docs/resources/device_acl_policy_definition.md index 449ca3c4..e4b9b77a 100644 --- a/docs/resources/device_acl_policy_definition.md +++ b/docs/resources/device_acl_policy_definition.md @@ -3,12 +3,12 @@ page_title: "sdwan_device_acl_policy_definition Resource - terraform-provider-sdwan" subcategory: "Localized Policies" description: |- - This resource can manage a Device ACL policy definition. + This resource can manage a Device ACL Policy Definition . --- # sdwan_device_acl_policy_definition (Resource) -This resource can manage a Device ACL policy definition. +This resource can manage a Device ACL Policy Definition . ## Example Usage @@ -56,9 +56,8 @@ resource "sdwan_device_acl_policy_definition" "example" { ### Read-Only -- `id` (String) The id of the policy definition -- `type` (String) The policy defintion type -- `version` (Number) The version of the policy definition +- `id` (String) The id of the object +- `version` (Number) The version of the object ### Nested Schema for `sequences` @@ -67,6 +66,7 @@ Required: - `id` (Number) Sequence ID - Range: `1`-`65534` +- `name` (String) Sequence name Optional: @@ -76,7 +76,6 @@ Optional: - `ip_type` (String) IP version, either `ipv4` or `ipv6` - Choices: `ipv4`, `ipv6` - `match_entries` (Attributes List) List of match entries (see [below for nested schema](#nestedatt--sequences--match_entries)) -- `name` (String) Sequence name ### Nested Schema for `sequences.action_entries` @@ -104,7 +103,7 @@ Optional: - `destination_data_prefix_list_id` (String) Destination data prefix list ID - `destination_data_prefix_list_version` (Number) Destination data prefix list version - `destination_ip` (String) Destination IP prefix -- `destination_port` (Number) Destination port +- `destination_port` (Number) Destination port, only `22` and `161` supported - Range: `0`-`65535` - `source_data_prefix_list_id` (String) Source data prefix list ID - `source_data_prefix_list_version` (Number) Source data prefix list version diff --git a/gen/definitions/policy_definitions/device_acl.yaml b/gen/definitions/generic/device_acl_policy_definition.yaml similarity index 75% rename from gen/definitions/policy_definitions/device_acl.yaml rename to gen/definitions/generic/device_acl_policy_definition.yaml index 2805952b..3820710f 100644 --- a/gen/definitions/policy_definitions/device_acl.yaml +++ b/gen/definitions/generic/device_acl_policy_definition.yaml @@ -1,9 +1,24 @@ --- -name: Device ACL -type: deviceAccessPolicy +name: Device ACL Policy Definition +rest_endpoint: /template/policy/definition/deviceaccesspolicy/ +has_version: true +id_attribute: definitionId doc_category: Localized Policies -skip_templates: [model.go, resource.go] attributes: + - model_name: type + value: deviceAccessPolicy + - model_name: name + tf_name: name + type: String + mandatory: true + description: The name of the policy definition + example: Example + - model_name: description + tf_name: description + type: String + mandatory: true + description: The description of the policy definition + example: My description - model_name: type tf_name: default_action data_path: [defaultAction] @@ -19,6 +34,7 @@ attributes: - model_name: sequenceId tf_name: id type: Int64 + id: true mandatory: true description: Sequence ID min_int: 1 @@ -33,6 +49,8 @@ attributes: - model_name: sequenceName tf_name: name type: String + id: true + mandatory: true description: Sequence name example: Sequence 10 - model_name: sequenceType @@ -52,6 +70,7 @@ attributes: - model_name: field tf_name: type type: String + id: true mandatory: true enum_values: [ @@ -66,18 +85,27 @@ attributes: example: destinationPort - model_name: value tf_name: source_ip + conditional_attribute: + name: type + value: sourceIp type: String description: Source IP prefix exclude_test: true example: 10.0.0.0/8 - model_name: value tf_name: destination_ip + conditional_attribute: + name: type + value: destinationIp type: String description: Destination IP prefix exclude_test: true example: 192.168.0.0/16 - model_name: value tf_name: source_port + conditional_attribute: + name: type + value: sourcePort type: Int64 model_type_string: true description: Source port @@ -87,6 +115,9 @@ attributes: example: 8000 - model_name: value tf_name: destination_port + conditional_attribute: + name: type + value: destinationPort type: Int64 model_type_string: true description: Destination port, only `22` and `161` supported @@ -95,24 +126,30 @@ attributes: example: 22 - model_name: ref tf_name: source_data_prefix_list_id + conditional_attribute: + name: type + value: sourceDataPrefixList type: String description: Source data prefix list ID exclude_test: true example: 2081c2f4-3f9f-4fee-8078-dcc8904e368d - tf_name: source_data_prefix_list_version tf_only: true - type: Int64 + type: Version description: Source data prefix list version exclude_test: true - model_name: ref tf_name: destination_data_prefix_list_id + conditional_attribute: + name: type + value: destinationDataPrefixList type: String description: Destination data prefix list ID exclude_test: true example: 2081c2f4-3f9f-4fee-8078-dcc8904e368d - tf_name: destination_data_prefix_list_version tf_only: true - type: Int64 + type: Version description: Destination data prefix list version exclude_test: true - model_name: actions @@ -123,12 +160,16 @@ attributes: - model_name: type tf_name: type type: String + id: true mandatory: true enum_values: [count] description: Type of action entry example: count - model_name: parameter tf_name: counter_name + conditional_attribute: + name: type + value: count type: String description: Counter name example: count1 diff --git a/internal/provider/data_source_sdwan_device_acl_policy_definition.go b/internal/provider/data_source_sdwan_device_acl_policy_definition.go index 0977d87b..3e4d7067 100644 --- a/internal/provider/data_source_sdwan_device_acl_policy_definition.go +++ b/internal/provider/data_source_sdwan_device_acl_policy_definition.go @@ -50,19 +50,15 @@ func (d *DeviceACLPolicyDefinitionDataSource) Metadata(_ context.Context, req da func (d *DeviceACLPolicyDefinitionDataSource) 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 ACL policy definition.", + MarkdownDescription: "This data source can read the Device ACL Policy Definition .", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "The id of the policy definition", + MarkdownDescription: "The id of the object", Required: true, }, "version": schema.Int64Attribute{ - MarkdownDescription: "The version of the policy definition", - Computed: true, - }, - "type": schema.StringAttribute{ - MarkdownDescription: "The policy definition type", + MarkdownDescription: "The version of the object", Computed: true, }, "name": schema.StringAttribute{ @@ -174,7 +170,7 @@ func (d *DeviceACLPolicyDefinitionDataSource) Configure(_ context.Context, req d } func (d *DeviceACLPolicyDefinitionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config DeviceACL + var config DeviceACLPolicyDefinition // Read config diags := req.Config.Get(ctx, &config) diff --git a/internal/provider/data_source_sdwan_device_acl_policy_definition_test.go b/internal/provider/data_source_sdwan_device_acl_policy_definition_test.go index c4fc4460..4633a433 100644 --- a/internal/provider/data_source_sdwan_device_acl_policy_definition_test.go +++ b/internal/provider/data_source_sdwan_device_acl_policy_definition_test.go @@ -33,6 +33,8 @@ func TestAccDataSourceSdwanDeviceACLPolicyDefinition(t *testing.T) { { Config: testAccDataSourceSdwanDeviceACLPolicyDefinitionConfig, Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.sdwan_device_acl_policy_definition.test", "name", "Example"), + resource.TestCheckResourceAttr("data.sdwan_device_acl_policy_definition.test", "description", "My description"), resource.TestCheckResourceAttr("data.sdwan_device_acl_policy_definition.test", "default_action", "drop"), resource.TestCheckResourceAttr("data.sdwan_device_acl_policy_definition.test", "sequences.0.id", "10"), resource.TestCheckResourceAttr("data.sdwan_device_acl_policy_definition.test", "sequences.0.ip_type", "ipv4"), @@ -51,8 +53,8 @@ func TestAccDataSourceSdwanDeviceACLPolicyDefinition(t *testing.T) { const testAccDataSourceSdwanDeviceACLPolicyDefinitionConfig = ` resource "sdwan_device_acl_policy_definition" "test" { - name = "TF_TEST_MIN" - description = "Terraform integration test" + name = "Example" + description = "My description" default_action = "drop" sequences = [{ id = 10 diff --git a/internal/provider/model_sdwan_device_acl_policy_definition.go b/internal/provider/model_sdwan_device_acl_policy_definition.go index 685f0664..a5c459ba 100644 --- a/internal/provider/model_sdwan_device_acl_policy_definition.go +++ b/internal/provider/model_sdwan_device_acl_policy_definition.go @@ -28,26 +28,25 @@ import ( "github.com/tidwall/sjson" ) -type DeviceACL struct { - Id types.String `tfsdk:"id"` - Version types.Int64 `tfsdk:"version"` - Type types.String `tfsdk:"type"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - DefaultAction types.String `tfsdk:"default_action"` - Sequences []DeviceACLSequences `tfsdk:"sequences"` +type DeviceACLPolicyDefinition struct { + Id types.String `tfsdk:"id"` + Version types.Int64 `tfsdk:"version"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + DefaultAction types.String `tfsdk:"default_action"` + Sequences []DeviceACLPolicyDefinitionSequences `tfsdk:"sequences"` } -type DeviceACLSequences struct { - Id types.Int64 `tfsdk:"id"` - IpType types.String `tfsdk:"ip_type"` - Name types.String `tfsdk:"name"` - BaseAction types.String `tfsdk:"base_action"` - MatchEntries []DeviceACLSequencesMatchEntries `tfsdk:"match_entries"` - ActionEntries []DeviceACLSequencesActionEntries `tfsdk:"action_entries"` +type DeviceACLPolicyDefinitionSequences struct { + Id types.Int64 `tfsdk:"id"` + IpType types.String `tfsdk:"ip_type"` + Name types.String `tfsdk:"name"` + BaseAction types.String `tfsdk:"base_action"` + MatchEntries []DeviceACLPolicyDefinitionSequencesMatchEntries `tfsdk:"match_entries"` + ActionEntries []DeviceACLPolicyDefinitionSequencesActionEntries `tfsdk:"action_entries"` } -type DeviceACLSequencesMatchEntries struct { +type DeviceACLPolicyDefinitionSequencesMatchEntries struct { Type types.String `tfsdk:"type"` SourceIp types.String `tfsdk:"source_ip"` DestinationIp types.String `tfsdk:"destination_ip"` @@ -58,25 +57,25 @@ type DeviceACLSequencesMatchEntries struct { DestinationDataPrefixListId types.String `tfsdk:"destination_data_prefix_list_id"` DestinationDataPrefixListVersion types.Int64 `tfsdk:"destination_data_prefix_list_version"` } -type DeviceACLSequencesActionEntries struct { +type DeviceACLPolicyDefinitionSequencesActionEntries struct { Type types.String `tfsdk:"type"` CounterName types.String `tfsdk:"counter_name"` } -func (data DeviceACL) getType() string { - return "deviceAccessPolicy" -} - -func (data DeviceACL) toBody(ctx context.Context) string { - body, _ := sjson.Set("", "name", data.Name.ValueString()) - body, _ = sjson.Set(body, "description", data.Description.ValueString()) +func (data DeviceACLPolicyDefinition) toBody(ctx context.Context) string { + body := "" body, _ = sjson.Set(body, "type", "deviceAccessPolicy") - path := "" + if !data.Name.IsNull() { + body, _ = sjson.Set(body, "name", data.Name.ValueString()) + } + if !data.Description.IsNull() { + body, _ = sjson.Set(body, "description", data.Description.ValueString()) + } if !data.DefaultAction.IsNull() { - body, _ = sjson.Set(body, path+"defaultAction.type", data.DefaultAction.ValueString()) + body, _ = sjson.Set(body, "defaultAction.type", data.DefaultAction.ValueString()) } if len(data.Sequences) > 0 { - body, _ = sjson.Set(body, path+"sequences", []interface{}{}) + body, _ = sjson.Set(body, "sequences", []interface{}{}) for _, item := range data.Sequences { itemBody := "" if !item.Id.IsNull() { @@ -99,22 +98,22 @@ func (data DeviceACL) toBody(ctx context.Context) string { if !childItem.Type.IsNull() { itemChildBody, _ = sjson.Set(itemChildBody, "field", childItem.Type.ValueString()) } - if !childItem.SourceIp.IsNull() { + if !childItem.SourceIp.IsNull() && childItem.Type.ValueString() == "sourceIp" { itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.SourceIp.ValueString()) } - if !childItem.DestinationIp.IsNull() { + if !childItem.DestinationIp.IsNull() && childItem.Type.ValueString() == "destinationIp" { itemChildBody, _ = sjson.Set(itemChildBody, "value", childItem.DestinationIp.ValueString()) } - if !childItem.SourcePort.IsNull() { + if !childItem.SourcePort.IsNull() && childItem.Type.ValueString() == "sourcePort" { itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.SourcePort.ValueInt64())) } - if !childItem.DestinationPort.IsNull() { + if !childItem.DestinationPort.IsNull() && childItem.Type.ValueString() == "destinationPort" { itemChildBody, _ = sjson.Set(itemChildBody, "value", fmt.Sprint(childItem.DestinationPort.ValueInt64())) } - if !childItem.SourceDataPrefixListId.IsNull() { + if !childItem.SourceDataPrefixListId.IsNull() && childItem.Type.ValueString() == "sourceDataPrefixList" { itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.SourceDataPrefixListId.ValueString()) } - if !childItem.DestinationDataPrefixListId.IsNull() { + if !childItem.DestinationDataPrefixListId.IsNull() && childItem.Type.ValueString() == "destinationDataPrefixList" { itemChildBody, _ = sjson.Set(itemChildBody, "ref", childItem.DestinationDataPrefixListId.ValueString()) } itemBody, _ = sjson.SetRaw(itemBody, "match.entries.-1", itemChildBody) @@ -127,19 +126,19 @@ func (data DeviceACL) toBody(ctx context.Context) string { if !childItem.Type.IsNull() { itemChildBody, _ = sjson.Set(itemChildBody, "type", childItem.Type.ValueString()) } - if !childItem.CounterName.IsNull() { + if !childItem.CounterName.IsNull() && childItem.Type.ValueString() == "count" { itemChildBody, _ = sjson.Set(itemChildBody, "parameter", childItem.CounterName.ValueString()) } itemBody, _ = sjson.SetRaw(itemBody, "actions.-1", itemChildBody) } } - body, _ = sjson.SetRaw(body, path+"sequences.-1", itemBody) + body, _ = sjson.SetRaw(body, "sequences.-1", itemBody) } } return body } -func (data *DeviceACL) fromBody(ctx context.Context, res gjson.Result) { +func (data *DeviceACLPolicyDefinition) fromBody(ctx context.Context, res gjson.Result) { if value := res.Get("name"); value.Exists() { data.Name = types.StringValue(value.String()) } else { @@ -150,21 +149,15 @@ func (data *DeviceACL) fromBody(ctx context.Context, res gjson.Result) { } else { data.Description = types.StringNull() } - if value := res.Get("type"); value.Exists() { - data.Type = types.StringValue(value.String()) - } else { - data.Type = types.StringNull() - } - path := "" - if value := res.Get(path + "defaultAction.type"); value.Exists() { + if value := res.Get("defaultAction.type"); value.Exists() { data.DefaultAction = types.StringValue(value.String()) } else { data.DefaultAction = types.StringNull() } - if value := res.Get(path + "sequences"); value.Exists() { - data.Sequences = make([]DeviceACLSequences, 0) + if value := res.Get("sequences"); value.Exists() { + data.Sequences = make([]DeviceACLPolicyDefinitionSequences, 0) value.ForEach(func(k, v gjson.Result) bool { - item := DeviceACLSequences{} + item := DeviceACLPolicyDefinitionSequences{} if cValue := v.Get("sequenceId"); cValue.Exists() { item.Id = types.Int64Value(cValue.Int()) } else { @@ -186,40 +179,40 @@ func (data *DeviceACL) fromBody(ctx context.Context, res gjson.Result) { item.BaseAction = types.StringNull() } if cValue := v.Get("match.entries"); cValue.Exists() { - item.MatchEntries = make([]DeviceACLSequencesMatchEntries, 0) + item.MatchEntries = make([]DeviceACLPolicyDefinitionSequencesMatchEntries, 0) cValue.ForEach(func(ck, cv gjson.Result) bool { - cItem := DeviceACLSequencesMatchEntries{} + cItem := DeviceACLPolicyDefinitionSequencesMatchEntries{} if ccValue := cv.Get("field"); ccValue.Exists() { cItem.Type = types.StringValue(ccValue.String()) } else { cItem.Type = types.StringNull() } - if ccValue := cv.Get("value"); cItem.Type.ValueString() == "sourceIp" && ccValue.Exists() { + if ccValue := cv.Get("value"); ccValue.Exists() && cItem.Type.ValueString() == "sourceIp" { cItem.SourceIp = types.StringValue(ccValue.String()) } else { cItem.SourceIp = types.StringNull() } - if ccValue := cv.Get("value"); cItem.Type.ValueString() == "destinationIp" && ccValue.Exists() { + if ccValue := cv.Get("value"); ccValue.Exists() && cItem.Type.ValueString() == "destinationIp" { cItem.DestinationIp = types.StringValue(ccValue.String()) } else { cItem.DestinationIp = types.StringNull() } - if ccValue := cv.Get("value"); cItem.Type.ValueString() == "sourcePort" && ccValue.Exists() { + if ccValue := cv.Get("value"); ccValue.Exists() && cItem.Type.ValueString() == "sourcePort" { cItem.SourcePort = types.Int64Value(ccValue.Int()) } else { cItem.SourcePort = types.Int64Null() } - if ccValue := cv.Get("value"); cItem.Type.ValueString() == "destinationPort" && ccValue.Exists() { + if ccValue := cv.Get("value"); ccValue.Exists() && cItem.Type.ValueString() == "destinationPort" { cItem.DestinationPort = types.Int64Value(ccValue.Int()) } else { cItem.DestinationPort = types.Int64Null() } - if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "sourceDataPrefixList" && ccValue.Exists() { + if ccValue := cv.Get("ref"); ccValue.Exists() && cItem.Type.ValueString() == "sourceDataPrefixList" { cItem.SourceDataPrefixListId = types.StringValue(ccValue.String()) } else { cItem.SourceDataPrefixListId = types.StringNull() } - if ccValue := cv.Get("ref"); cItem.Type.ValueString() == "destinationDataPrefixList" && ccValue.Exists() { + if ccValue := cv.Get("ref"); ccValue.Exists() && cItem.Type.ValueString() == "destinationDataPrefixList" { cItem.DestinationDataPrefixListId = types.StringValue(ccValue.String()) } else { cItem.DestinationDataPrefixListId = types.StringNull() @@ -229,15 +222,15 @@ func (data *DeviceACL) fromBody(ctx context.Context, res gjson.Result) { }) } if cValue := v.Get("actions"); cValue.Exists() { - item.ActionEntries = make([]DeviceACLSequencesActionEntries, 0) + item.ActionEntries = make([]DeviceACLPolicyDefinitionSequencesActionEntries, 0) cValue.ForEach(func(ck, cv gjson.Result) bool { - cItem := DeviceACLSequencesActionEntries{} + cItem := DeviceACLPolicyDefinitionSequencesActionEntries{} if ccValue := cv.Get("type"); ccValue.Exists() { cItem.Type = types.StringValue(ccValue.String()) } else { cItem.Type = types.StringNull() } - if ccValue := cv.Get("parameter"); ccValue.Exists() { + if ccValue := cv.Get("parameter"); ccValue.Exists() && cItem.Type.ValueString() == "count" { cItem.CounterName = types.StringValue(ccValue.String()) } else { cItem.CounterName = types.StringNull() @@ -250,9 +243,12 @@ func (data *DeviceACL) fromBody(ctx context.Context, res gjson.Result) { return true }) } + + data.updateVersions(ctx) + } -func (data *DeviceACL) hasChanges(ctx context.Context, state *DeviceACL) bool { +func (data *DeviceACLPolicyDefinition) hasChanges(ctx context.Context, state *DeviceACLPolicyDefinition) bool { hasChanges := false if !data.Name.Equal(state.Name) { hasChanges = true @@ -323,42 +319,37 @@ func (data *DeviceACL) hasChanges(ctx context.Context, state *DeviceACL) bool { return hasChanges } -func (data *DeviceACL) getMatchSourceDataPrefixListVersion(ctx context.Context, name string, id int64) types.Int64 { - for _, item := range data.Sequences { - if item.Name.ValueString() == name && item.Id.ValueInt64() == id { - for _, cItem := range item.MatchEntries { - if cItem.Type.ValueString() == "sourceDataPrefixList" { - return cItem.SourceDataPrefixListVersion - } +func (data *DeviceACLPolicyDefinition) updateVersions(ctx context.Context) { + state := *data + for i := range data.Sequences { + dataKeys := [...]string{fmt.Sprintf("%v", data.Sequences[i].Id.ValueInt64()), fmt.Sprintf("%v", data.Sequences[i].Name.ValueString())} + stateIndex := -1 + for j := range state.Sequences { + stateKeys := [...]string{fmt.Sprintf("%v", state.Sequences[j].Id.ValueInt64()), fmt.Sprintf("%v", state.Sequences[j].Name.ValueString())} + if dataKeys == stateKeys { + stateIndex = j + break } } - } - return types.Int64Null() -} - -func (data *DeviceACL) getMatchDestinationDataPrefixListVersion(ctx context.Context, name string, id int64) types.Int64 { - for _, item := range data.Sequences { - if item.Name.ValueString() == name && item.Id.ValueInt64() == id { - for _, cItem := range item.MatchEntries { - if cItem.Type.ValueString() == "destinationDataPrefixList" { - return cItem.DestinationDataPrefixListVersion + for ii := range data.Sequences[i].MatchEntries { + cDataKeys := [...]string{fmt.Sprintf("%v", data.Sequences[i].MatchEntries[ii].Type.ValueString())} + cStateIndex := -1 + for jj := range state.Sequences[stateIndex].MatchEntries { + cStateKeys := [...]string{fmt.Sprintf("%v", state.Sequences[stateIndex].MatchEntries[jj].Type.ValueString())} + if cDataKeys == cStateKeys { + cStateIndex = jj + break } } - } - } - return types.Int64Null() -} - -func (data *DeviceACL) updateVersions(ctx context.Context, state DeviceACL) { - for s := range data.Sequences { - id := data.Sequences[s].Id.ValueInt64() - name := data.Sequences[s].Name.ValueString() - for m := range data.Sequences[s].MatchEntries { - t := data.Sequences[s].MatchEntries[m].Type.ValueString() - if t == "sourceDataPrefixList" { - data.Sequences[s].MatchEntries[m].SourceDataPrefixListVersion = state.getMatchSourceDataPrefixListVersion(ctx, name, id) - } else if t == "destinationDataPrefixList" { - data.Sequences[s].MatchEntries[m].DestinationDataPrefixListVersion = state.getMatchDestinationDataPrefixListVersion(ctx, name, id) + if cStateIndex >= -1 { + data.Sequences[i].MatchEntries[ii].SourceDataPrefixListVersion = state.Sequences[stateIndex].MatchEntries[cStateIndex].SourceDataPrefixListVersion + } else { + data.Sequences[i].MatchEntries[ii].SourceDataPrefixListVersion = types.Int64Null() + } + if cStateIndex >= -1 { + data.Sequences[i].MatchEntries[ii].DestinationDataPrefixListVersion = state.Sequences[stateIndex].MatchEntries[cStateIndex].DestinationDataPrefixListVersion + } else { + data.Sequences[i].MatchEntries[ii].DestinationDataPrefixListVersion = types.Int64Null() } } } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 0270d820..02aab563 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -281,7 +281,6 @@ func (p *SdwanProvider) Resources(ctx context.Context) []func() resource.Resourc NewStandardCommunityListPolicyObjectResource, NewTLOCListPolicyObjectResource, NewVPNListPolicyObjectResource, - NewDeviceACLPolicyDefinitionResource, NewQoSMapPolicyDefinitionResource, NewRewriteRulePolicyDefinitionResource, NewRoutePolicyDefinitionResource, @@ -289,6 +288,7 @@ func (p *SdwanProvider) Resources(ctx context.Context) []func() resource.Resourc NewApplicationAwareRoutingPolicyDefinitionResource, NewCflowdPolicyDefinitionResource, NewCustomControlTopologyPolicyDefinitionResource, + NewDeviceACLPolicyDefinitionResource, NewHubAndSpokeTopologyPolicyDefinitionResource, NewMeshTopologyPolicyDefinitionResource, NewTrafficDataPolicyDefinitionResource, @@ -342,7 +342,6 @@ func (p *SdwanProvider) DataSources(ctx context.Context) []func() datasource.Dat NewStandardCommunityListPolicyObjectDataSource, NewTLOCListPolicyObjectDataSource, NewVPNListPolicyObjectDataSource, - NewDeviceACLPolicyDefinitionDataSource, NewQoSMapPolicyDefinitionDataSource, NewRewriteRulePolicyDefinitionDataSource, NewRoutePolicyDefinitionDataSource, @@ -350,6 +349,7 @@ func (p *SdwanProvider) DataSources(ctx context.Context) []func() datasource.Dat NewApplicationAwareRoutingPolicyDefinitionDataSource, NewCflowdPolicyDefinitionDataSource, NewCustomControlTopologyPolicyDefinitionDataSource, + NewDeviceACLPolicyDefinitionDataSource, NewHubAndSpokeTopologyPolicyDefinitionDataSource, NewMeshTopologyPolicyDefinitionDataSource, NewTrafficDataPolicyDefinitionDataSource, diff --git a/internal/provider/resource_sdwan_device_acl_policy_definition.go b/internal/provider/resource_sdwan_device_acl_policy_definition.go index d7598914..9fc1a108 100644 --- a/internal/provider/resource_sdwan_device_acl_policy_definition.go +++ b/internal/provider/resource_sdwan_device_acl_policy_definition.go @@ -59,33 +59,26 @@ func (r *DeviceACLPolicyDefinitionResource) Metadata(ctx context.Context, req re func (r *DeviceACLPolicyDefinitionResource) 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 ACL policy definition.").String, + MarkdownDescription: helpers.NewAttributeDescription("This resource can manage a Device ACL Policy Definition .").String, Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "The id of the policy definition", + MarkdownDescription: "The id of the object", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "version": schema.Int64Attribute{ - MarkdownDescription: "The version of the policy definition", + MarkdownDescription: "The version of the object", Computed: true, }, - "type": schema.StringAttribute{ - MarkdownDescription: "The policy defintion type", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, "name": schema.StringAttribute{ - MarkdownDescription: "The name of the policy definition", + MarkdownDescription: helpers.NewAttributeDescription("The name of the policy definition").String, Required: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "The description of the policy definition", + MarkdownDescription: helpers.NewAttributeDescription("The description of the policy definition").String, Required: true, }, "default_action": schema.StringAttribute{ @@ -116,7 +109,7 @@ func (r *DeviceACLPolicyDefinitionResource) Schema(ctx context.Context, req reso }, "name": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("Sequence name").String, - Optional: true, + Required: true, }, "base_action": schema.StringAttribute{ MarkdownDescription: helpers.NewAttributeDescription("Base action, either `accept` or `drop`").AddStringEnumDescription("accept", "drop").String, @@ -153,7 +146,7 @@ func (r *DeviceACLPolicyDefinitionResource) Schema(ctx context.Context, req reso }, }, "destination_port": schema.Int64Attribute{ - MarkdownDescription: helpers.NewAttributeDescription("Destination port").AddIntegerRangeDescription(0, 65535).String, + MarkdownDescription: helpers.NewAttributeDescription("Destination port, only `22` and `161` supported").AddIntegerRangeDescription(0, 65535).String, Optional: true, Validators: []validator.Int64{ int64validator.Between(0, 65535), @@ -214,7 +207,7 @@ func (r *DeviceACLPolicyDefinitionResource) Configure(_ context.Context, req res } func (r *DeviceACLPolicyDefinitionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var plan DeviceACL + var plan DeviceACLPolicyDefinition // Read plan diags := req.Plan.Get(ctx, &plan) @@ -228,7 +221,7 @@ func (r *DeviceACLPolicyDefinitionResource) Create(ctx context.Context, req reso // Create object body := plan.toBody(ctx) - res, err := r.client.Post("/template/policy/definition/deviceaccesspolicy", body) + res, err := r.client.Post("/template/policy/definition/deviceaccesspolicy/", body) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST), got error: %s, %s", err, res.String())) return @@ -236,7 +229,6 @@ func (r *DeviceACLPolicyDefinitionResource) Create(ctx context.Context, req reso plan.Id = types.StringValue(res.Get("definitionId").String()) plan.Version = types.Int64Value(0) - plan.Type = types.StringValue(plan.getType()) tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Name.ValueString())) @@ -245,7 +237,7 @@ func (r *DeviceACLPolicyDefinitionResource) Create(ctx context.Context, req reso } func (r *DeviceACLPolicyDefinitionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state, oldState DeviceACL + var state DeviceACLPolicyDefinition // Read state diags := req.State.Get(ctx, &state) @@ -253,11 +245,6 @@ func (r *DeviceACLPolicyDefinitionResource) Read(ctx context.Context, req resour if resp.Diagnostics.HasError() { return } - diags = req.State.Get(ctx, &oldState) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Name.String())) @@ -271,7 +258,6 @@ func (r *DeviceACLPolicyDefinitionResource) Read(ctx context.Context, req resour } state.fromBody(ctx, res) - state.updateVersions(ctx, oldState) tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Name.ValueString())) @@ -280,7 +266,7 @@ func (r *DeviceACLPolicyDefinitionResource) Read(ctx context.Context, req resour } func (r *DeviceACLPolicyDefinitionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan, state DeviceACL + var plan, state DeviceACLPolicyDefinition // Read plan diags := req.Plan.Get(ctx, &plan) @@ -313,7 +299,6 @@ func (r *DeviceACLPolicyDefinitionResource) Update(ctx context.Context, req reso } else { tflog.Debug(ctx, fmt.Sprintf("%s: No changes detected", plan.Name.ValueString())) } - plan.Version = types.Int64Value(state.Version.ValueInt64() + 1) tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Name.ValueString())) @@ -323,7 +308,7 @@ func (r *DeviceACLPolicyDefinitionResource) Update(ctx context.Context, req reso } func (r *DeviceACLPolicyDefinitionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state DeviceACL + var state DeviceACLPolicyDefinition // Read state diags := req.State.Get(ctx, &state) diff --git a/internal/provider/resource_sdwan_device_acl_policy_definition_test.go b/internal/provider/resource_sdwan_device_acl_policy_definition_test.go index c3c27438..9d547628 100644 --- a/internal/provider/resource_sdwan_device_acl_policy_definition_test.go +++ b/internal/provider/resource_sdwan_device_acl_policy_definition_test.go @@ -33,6 +33,8 @@ func TestAccSdwanDeviceACLPolicyDefinition(t *testing.T) { { Config: testAccSdwanDeviceACLPolicyDefinitionConfig_all(), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("sdwan_device_acl_policy_definition.test", "name", "Example"), + resource.TestCheckResourceAttr("sdwan_device_acl_policy_definition.test", "description", "My description"), resource.TestCheckResourceAttr("sdwan_device_acl_policy_definition.test", "default_action", "drop"), resource.TestCheckResourceAttr("sdwan_device_acl_policy_definition.test", "sequences.0.id", "10"), resource.TestCheckResourceAttr("sdwan_device_acl_policy_definition.test", "sequences.0.ip_type", "ipv4"), @@ -51,8 +53,8 @@ func TestAccSdwanDeviceACLPolicyDefinition(t *testing.T) { func testAccSdwanDeviceACLPolicyDefinitionConfig_all() string { return ` resource "sdwan_device_acl_policy_definition" "test" { - name = "TF_TEST_ALL" - description = "Terraform integration test" + name = "Example" + description = "My description" default_action = "drop" sequences = [{ id = 10