diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a7651e..38148e0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
## 0.1.11 (unreleased)
+- Add `catalystcenter_fabric_port_assignment` resource and data source
- Add `catalystcenter_wireless_ssid` resource and data source
- Add `catalystcenter_site` data source
- Add `catalystcenter_fabric_vlan_to_ssid` resource and data source
diff --git a/docs/data-sources/fabric_port_assignment.md b/docs/data-sources/fabric_port_assignment.md
new file mode 100644
index 0000000..5e871c6
--- /dev/null
+++ b/docs/data-sources/fabric_port_assignment.md
@@ -0,0 +1,48 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "catalystcenter_fabric_port_assignment Data Source - terraform-provider-catalystcenter"
+subcategory: "SDA"
+description: |-
+ This data source can read the Fabric Port Assignment.
+---
+
+# catalystcenter_fabric_port_assignment (Data Source)
+
+This data source can read the Fabric Port Assignment.
+
+## Example Usage
+
+```terraform
+data "catalystcenter_fabric_port_assignment" "example" {
+ fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
+}
+```
+
+
+## Schema
+
+### Required
+
+- `fabric_id` (String) ID of the fabric the device is assigned to
+- `network_device_id` (String) Network device ID of the port assignment
+
+### Read-Only
+
+- `id` (String) The id of the object
+- `port_assignments` (Attributes List) List of port assignments in SD-Access fabric (see [below for nested schema](#nestedatt--port_assignments))
+
+
+### Nested Schema for `port_assignments`
+
+Read-Only:
+
+- `authenticate_template_name` (String) Authenticate template name of the port assignment
+- `connected_device_type` (String) Connected device type of the port assignment
+- `data_vlan_name` (String) Data VLAN name of the port assignment
+- `fabric_id` (String) ID of the fabric the device is assigned to
+- `interface_description` (String) Interface description of the port assignment
+- `interface_name` (String) Interface name of the port assignment
+- `network_device_id` (String) Network device ID of the port assignment
+- `security_group_name` (String) Security group name of the port assignment
+- `voice_vlan_name` (String) Voice VLAN name of the port assignment
diff --git a/docs/guides/changelog.md b/docs/guides/changelog.md
index 4f8a03b..74f83c3 100644
--- a/docs/guides/changelog.md
+++ b/docs/guides/changelog.md
@@ -9,6 +9,7 @@ description: |-
## 0.1.11 (unreleased)
+- Add `catalystcenter_fabric_port_assignment` resource and data source
- Add `catalystcenter_wireless_ssid` resource and data source
- Add `catalystcenter_site` data source
- Add `catalystcenter_fabric_vlan_to_ssid` resource and data source
diff --git a/docs/resources/fabric_port_assignment.md b/docs/resources/fabric_port_assignment.md
new file mode 100644
index 0000000..6c84ee3
--- /dev/null
+++ b/docs/resources/fabric_port_assignment.md
@@ -0,0 +1,67 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "catalystcenter_fabric_port_assignment Resource - terraform-provider-catalystcenter"
+subcategory: "SDA"
+description: |-
+ Manages Port Assignments in SD-Access Fabric
+---
+
+# catalystcenter_fabric_port_assignment (Resource)
+
+Manages Port Assignments in SD-Access Fabric
+
+## Example Usage
+
+```terraform
+resource "catalystcenter_fabric_port_assignment" "example" {
+ fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
+ port_assignments = [
+ {
+ fabric_id = "c4b85bb2-ce3f-4db9-a32b-e439a388ac2f"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
+ interface_name = "GigabitEthernet1/0/2"
+ connected_device_type = "USER_DEVICE"
+ data_vlan_name = "DATA_VLAN"
+ voice_vlan_name = "VOICE_VLAN"
+ authenticate_template_name = "No Authentication"
+ }
+ ]
+}
+```
+
+
+## Schema
+
+### Required
+
+- `network_device_id` (String) Network device ID of the port assignment
+- `port_assignments` (Attributes List) List of port assignments in SD-Access fabric (see [below for nested schema](#nestedatt--port_assignments))
+
+### Optional
+
+- `fabric_id` (String) ID of the fabric the device is assigned to
+
+### Read-Only
+
+- `id` (String) The id of the object
+
+
+### Nested Schema for `port_assignments`
+
+Required:
+
+- `connected_device_type` (String) Connected device type of the port assignment
+ - Choices: `USER_DEVICE`, `ACCESS_POINT`, `TRUNKING_DEVICE`, `AUTHENTICATOR_SWITCH`, `SUPPLICANT_BASED_EXTENDED_NODE`
+- `fabric_id` (String) ID of the fabric the device is assigned to
+- `interface_name` (String) Interface name of the port assignment
+- `network_device_id` (String) Network device ID of the port assignment
+
+Optional:
+
+- `authenticate_template_name` (String) Authenticate template name of the port assignment
+ - Choices: `No Authentication`, `Open Authentication`, `Closed Authentication`, `Low Impact`
+- `data_vlan_name` (String) Data VLAN name of the port assignment
+- `interface_description` (String) Interface description of the port assignment
+- `security_group_name` (String) Security group name of the port assignment
+- `voice_vlan_name` (String) Voice VLAN name of the port assignment
diff --git a/examples/data-sources/catalystcenter_fabric_port_assignment/data-source.tf b/examples/data-sources/catalystcenter_fabric_port_assignment/data-source.tf
new file mode 100644
index 0000000..9d1df74
--- /dev/null
+++ b/examples/data-sources/catalystcenter_fabric_port_assignment/data-source.tf
@@ -0,0 +1,4 @@
+data "catalystcenter_fabric_port_assignment" "example" {
+ fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
+}
diff --git a/examples/resources/catalystcenter_fabric_port_assignment/resource.tf b/examples/resources/catalystcenter_fabric_port_assignment/resource.tf
new file mode 100644
index 0000000..7c6f3ce
--- /dev/null
+++ b/examples/resources/catalystcenter_fabric_port_assignment/resource.tf
@@ -0,0 +1,15 @@
+resource "catalystcenter_fabric_port_assignment" "example" {
+ fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
+ port_assignments = [
+ {
+ fabric_id = "c4b85bb2-ce3f-4db9-a32b-e439a388ac2f"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
+ interface_name = "GigabitEthernet1/0/2"
+ connected_device_type = "USER_DEVICE"
+ data_vlan_name = "DATA_VLAN"
+ voice_vlan_name = "VOICE_VLAN"
+ authenticate_template_name = "No Authentication"
+ }
+ ]
+}
diff --git a/gen/definitions/fabric_port_assignment.yaml b/gen/definitions/fabric_port_assignment.yaml
new file mode 100644
index 0000000..2c83e3a
--- /dev/null
+++ b/gen/definitions/fabric_port_assignment.yaml
@@ -0,0 +1,85 @@
+---
+name: Fabric Port Assignment
+rest_endpoint: /dna/intent/api/v1/sda/portAssignments
+res_description: Manages Port Assignments in SD-Access Fabric
+no_update: true
+no_import: true
+data_source_no_id: true
+id_from_attribute: true
+root_list: true
+skip_minimum_test: true
+doc_category: SDA
+test_tags: [SDA]
+attributes:
+ - tf_name: fabric_id
+ write_only: true
+ query_param: true
+ delete_query_param: true
+ query_param_name: fabricId
+ delete_query_param_name: fabricId
+ type: String
+ description: ID of the fabric the device is assigned to
+ example: e02d9911-b0a7-435b-bb46-079d877d7b3e
+ - tf_name: network_device_id
+ write_only: true
+ id: true
+ query_param: true
+ delete_query_param: true
+ query_param_name: networkDeviceId
+ delete_query_param_name: networkDeviceId
+ type: String
+ description: Network device ID of the port assignment
+ example: 5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b
+ - tf_name: port_assignments
+ type: List
+ response_data_path: response
+ mandatory: true
+ description: List of port assignments in SD-Access fabric
+ attributes:
+ - model_name: fabricId
+ query_param: true
+ type: String
+ mandatory: true
+ description: ID of the fabric the device is assigned to
+ example: c4b85bb2-ce3f-4db9-a32b-e439a388ac2f
+ test_value: catalystcenter_fabric_site.test.id
+ - model_name: networkDeviceId
+ match_id: true
+ query_param: true
+ mandatory: true
+ description: Network device ID of the port assignment
+ type: String
+ example: 5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1
+ - model_name: interfaceName
+ query_param: true
+ mandatory: true
+ type: String
+ description: Interface name of the port assignment
+ example: GigabitEthernet1/0/2
+ - model_name: connectedDeviceType
+ mandatory: true
+ type: String
+ description: Connected device type of the port assignment
+ enum_values: [USER_DEVICE, ACCESS_POINT, TRUNKING_DEVICE, AUTHENTICATOR_SWITCH, SUPPLICANT_BASED_EXTENDED_NODE]
+ example: USER_DEVICE
+ - model_name: dataVlanName
+ type: String
+ description: Data VLAN name of the port assignment
+ example: DATA_VLAN
+ - model_name: voiceVlanName
+ type: String
+ description: Voice VLAN name of the port assignment
+ example: VOICE_VLAN
+ - model_name: authenticateTemplateName
+ type: String
+ description: Authenticate template name of the port assignment
+ enum_values: [No Authentication, Open Authentication, Closed Authentication, Low Impact]
+ example: No Authentication
+ - model_name: securityGroupName
+ type: String
+ description: Security group name of the port assignment
+ exclude_test: true
+ - model_name: interfaceDescription
+ type: String
+ description: Interface description of the port assignment
+ exclude_test: true
diff --git a/internal/provider/data_source_catalystcenter_fabric_port_assignment.go b/internal/provider/data_source_catalystcenter_fabric_port_assignment.go
new file mode 100644
index 0000000..b2fa077
--- /dev/null
+++ b/internal/provider/data_source_catalystcenter_fabric_port_assignment.go
@@ -0,0 +1,159 @@
+// 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/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ cc "github.com/netascode/go-catalystcenter"
+)
+
+// 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 = &FabricPortAssignmentDataSource{}
+ _ datasource.DataSourceWithConfigure = &FabricPortAssignmentDataSource{}
+)
+
+func NewFabricPortAssignmentDataSource() datasource.DataSource {
+ return &FabricPortAssignmentDataSource{}
+}
+
+type FabricPortAssignmentDataSource struct {
+ client *cc.Client
+}
+
+func (d *FabricPortAssignmentDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_fabric_port_assignment"
+}
+
+func (d *FabricPortAssignmentDataSource) 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 Fabric Port Assignment.",
+
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ MarkdownDescription: "The id of the object",
+ Computed: true,
+ },
+ "fabric_id": schema.StringAttribute{
+ MarkdownDescription: "ID of the fabric the device is assigned to",
+ Required: true,
+ },
+ "network_device_id": schema.StringAttribute{
+ MarkdownDescription: "Network device ID of the port assignment",
+ Required: true,
+ },
+ "port_assignments": schema.ListNestedAttribute{
+ MarkdownDescription: "List of port assignments in SD-Access fabric",
+ Computed: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "fabric_id": schema.StringAttribute{
+ MarkdownDescription: "ID of the fabric the device is assigned to",
+ Computed: true,
+ },
+ "network_device_id": schema.StringAttribute{
+ MarkdownDescription: "Network device ID of the port assignment",
+ Computed: true,
+ },
+ "interface_name": schema.StringAttribute{
+ MarkdownDescription: "Interface name of the port assignment",
+ Computed: true,
+ },
+ "connected_device_type": schema.StringAttribute{
+ MarkdownDescription: "Connected device type of the port assignment",
+ Computed: true,
+ },
+ "data_vlan_name": schema.StringAttribute{
+ MarkdownDescription: "Data VLAN name of the port assignment",
+ Computed: true,
+ },
+ "voice_vlan_name": schema.StringAttribute{
+ MarkdownDescription: "Voice VLAN name of the port assignment",
+ Computed: true,
+ },
+ "authenticate_template_name": schema.StringAttribute{
+ MarkdownDescription: "Authenticate template name of the port assignment",
+ Computed: true,
+ },
+ "security_group_name": schema.StringAttribute{
+ MarkdownDescription: "Security group name of the port assignment",
+ Computed: true,
+ },
+ "interface_description": schema.StringAttribute{
+ MarkdownDescription: "Interface description of the port assignment",
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (d *FabricPortAssignmentDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ d.client = req.ProviderData.(*CcProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+func (d *FabricPortAssignmentDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var config FabricPortAssignment
+
+ // Read config
+ diags := req.Config.Get(ctx, &config)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+
+ params := ""
+ params += "?fabricId=" + url.QueryEscape(config.FabricId.ValueString()) + "&networkDeviceId=" + url.QueryEscape(config.NetworkDeviceId.ValueString())
+ res, err := d.client.Get(config.getPath() + params)
+ 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_catalystcenter_fabric_port_assignment_test.go b/internal/provider/data_source_catalystcenter_fabric_port_assignment_test.go
new file mode 100644
index 0000000..95e1b8d
--- /dev/null
+++ b/internal/provider/data_source_catalystcenter_fabric_port_assignment_test.go
@@ -0,0 +1,85 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+ "os"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource
+func TestAccDataSourceCcFabricPortAssignment(t *testing.T) {
+ if os.Getenv("SDA") == "" {
+ t.Skip("skipping test, set environment variable SDA")
+ }
+ var checks []resource.TestCheckFunc
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.network_device_id", "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.interface_name", "GigabitEthernet1/0/2"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.connected_device_type", "USER_DEVICE"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.data_vlan_name", "DATA_VLAN"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.voice_vlan_name", "VOICE_VLAN"))
+ checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_port_assignment.test", "port_assignments.0.authenticate_template_name", "No Authentication"))
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceCcFabricPortAssignmentConfig(),
+ 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 testAccDataSourceCcFabricPortAssignmentConfig() string {
+ config := `resource "catalystcenter_fabric_port_assignment" "test" {` + "\n"
+ config += ` fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"` + "\n"
+ config += ` port_assignments = [{` + "\n"
+ config += ` fabric_id = catalystcenter_fabric_site.test.id` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"` + "\n"
+ config += ` interface_name = "GigabitEthernet1/0/2"` + "\n"
+ config += ` connected_device_type = "USER_DEVICE"` + "\n"
+ config += ` data_vlan_name = "DATA_VLAN"` + "\n"
+ config += ` voice_vlan_name = "VOICE_VLAN"` + "\n"
+ config += ` authenticate_template_name = "No Authentication"` + "\n"
+ config += ` }]` + "\n"
+ config += `}` + "\n"
+
+ config += `
+ data "catalystcenter_fabric_port_assignment" "test" {
+ fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"
+ network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
+ depends_on = [catalystcenter_fabric_port_assignment.test]
+ }
+ `
+ return config
+}
+
+// End of section. //template:end testAccDataSourceConfig
diff --git a/internal/provider/model_catalystcenter_fabric_port_assignment.go b/internal/provider/model_catalystcenter_fabric_port_assignment.go
new file mode 100644
index 0000000..01ee349
--- /dev/null
+++ b/internal/provider/model_catalystcenter_fabric_port_assignment.go
@@ -0,0 +1,269 @@
+// 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 FabricPortAssignment struct {
+ Id types.String `tfsdk:"id"`
+ FabricId types.String `tfsdk:"fabric_id"`
+ NetworkDeviceId types.String `tfsdk:"network_device_id"`
+ PortAssignments []FabricPortAssignmentPortAssignments `tfsdk:"port_assignments"`
+}
+
+type FabricPortAssignmentPortAssignments struct {
+ FabricId types.String `tfsdk:"fabric_id"`
+ NetworkDeviceId types.String `tfsdk:"network_device_id"`
+ InterfaceName types.String `tfsdk:"interface_name"`
+ ConnectedDeviceType types.String `tfsdk:"connected_device_type"`
+ DataVlanName types.String `tfsdk:"data_vlan_name"`
+ VoiceVlanName types.String `tfsdk:"voice_vlan_name"`
+ AuthenticateTemplateName types.String `tfsdk:"authenticate_template_name"`
+ SecurityGroupName types.String `tfsdk:"security_group_name"`
+ InterfaceDescription types.String `tfsdk:"interface_description"`
+}
+
+// End of section. //template:end types
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPath
+func (data FabricPortAssignment) getPath() string {
+ return "/dna/intent/api/v1/sda/portAssignments"
+}
+
+// End of section. //template:end getPath
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPathDelete
+
+// End of section. //template:end getPathDelete
+
+// Section below is generated&owned by "gen/generator.go". //template:begin toBody
+func (data FabricPortAssignment) toBody(ctx context.Context, state FabricPortAssignment) string {
+ body := "[]"
+ put := false
+ if state.Id.ValueString() != "" {
+ put = true
+ }
+ _ = put
+ if !data.FabricId.IsNull() {
+ body, _ = sjson.Set(body, "", data.FabricId.ValueString())
+ }
+ if !data.NetworkDeviceId.IsNull() {
+ body, _ = sjson.Set(body, "", data.NetworkDeviceId.ValueString())
+ }
+ if len(data.PortAssignments) > 0 {
+ body, _ = sjson.Set(body, "", []interface{}{})
+ for _, item := range data.PortAssignments {
+ itemBody := ""
+ if !item.FabricId.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "fabricId", item.FabricId.ValueString())
+ }
+ if !item.NetworkDeviceId.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "networkDeviceId", item.NetworkDeviceId.ValueString())
+ }
+ if !item.InterfaceName.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "interfaceName", item.InterfaceName.ValueString())
+ }
+ if !item.ConnectedDeviceType.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "connectedDeviceType", item.ConnectedDeviceType.ValueString())
+ }
+ if !item.DataVlanName.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "dataVlanName", item.DataVlanName.ValueString())
+ }
+ if !item.VoiceVlanName.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "voiceVlanName", item.VoiceVlanName.ValueString())
+ }
+ if !item.AuthenticateTemplateName.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "authenticateTemplateName", item.AuthenticateTemplateName.ValueString())
+ }
+ if !item.SecurityGroupName.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "securityGroupName", item.SecurityGroupName.ValueString())
+ }
+ if !item.InterfaceDescription.IsNull() {
+ itemBody, _ = sjson.Set(itemBody, "interfaceDescription", item.InterfaceDescription.ValueString())
+ }
+ body, _ = sjson.SetRaw(body, "-1", itemBody)
+ }
+ }
+ return body
+}
+
+// End of section. //template:end toBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
+func (data *FabricPortAssignment) fromBody(ctx context.Context, res gjson.Result) {
+
+ res = res.Get("response")
+ // Retrieve the 'id' attribute, if Data Source doesn't require id
+ if value := res.Get(""); value.Exists() {
+ data.Id = types.StringValue(value.String())
+ } else {
+ data.Id = types.StringNull()
+ }
+ if value := res; value.Exists() && len(value.Array()) > 0 {
+ data.PortAssignments = make([]FabricPortAssignmentPortAssignments, 0)
+ value.ForEach(func(k, v gjson.Result) bool {
+ item := FabricPortAssignmentPortAssignments{}
+ if cValue := v.Get("fabricId"); cValue.Exists() {
+ item.FabricId = types.StringValue(cValue.String())
+ } else {
+ item.FabricId = types.StringNull()
+ }
+ if cValue := v.Get("networkDeviceId"); cValue.Exists() {
+ item.NetworkDeviceId = types.StringValue(cValue.String())
+ } else {
+ item.NetworkDeviceId = types.StringNull()
+ }
+ if cValue := v.Get("interfaceName"); cValue.Exists() {
+ item.InterfaceName = types.StringValue(cValue.String())
+ } else {
+ item.InterfaceName = types.StringNull()
+ }
+ if cValue := v.Get("connectedDeviceType"); cValue.Exists() {
+ item.ConnectedDeviceType = types.StringValue(cValue.String())
+ } else {
+ item.ConnectedDeviceType = types.StringNull()
+ }
+ if cValue := v.Get("dataVlanName"); cValue.Exists() {
+ item.DataVlanName = types.StringValue(cValue.String())
+ } else {
+ item.DataVlanName = types.StringNull()
+ }
+ if cValue := v.Get("voiceVlanName"); cValue.Exists() {
+ item.VoiceVlanName = types.StringValue(cValue.String())
+ } else {
+ item.VoiceVlanName = types.StringNull()
+ }
+ if cValue := v.Get("authenticateTemplateName"); cValue.Exists() {
+ item.AuthenticateTemplateName = types.StringValue(cValue.String())
+ } else {
+ item.AuthenticateTemplateName = types.StringNull()
+ }
+ if cValue := v.Get("securityGroupName"); cValue.Exists() {
+ item.SecurityGroupName = types.StringValue(cValue.String())
+ } else {
+ item.SecurityGroupName = types.StringNull()
+ }
+ if cValue := v.Get("interfaceDescription"); cValue.Exists() {
+ item.InterfaceDescription = types.StringValue(cValue.String())
+ } else {
+ item.InterfaceDescription = types.StringNull()
+ }
+ data.PortAssignments = append(data.PortAssignments, item)
+ return true
+ })
+ }
+}
+
+// End of section. //template:end fromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin updateFromBody
+func (data *FabricPortAssignment) updateFromBody(ctx context.Context, res gjson.Result) {
+
+ res = res.Get("response")
+ for i := range data.PortAssignments {
+ keys := [...]string{"fabricId", "networkDeviceId", "interfaceName", "connectedDeviceType", "dataVlanName", "voiceVlanName", "authenticateTemplateName", "securityGroupName", "interfaceDescription"}
+ keyValues := [...]string{data.PortAssignments[i].FabricId.ValueString(), data.PortAssignments[i].NetworkDeviceId.ValueString(), data.PortAssignments[i].InterfaceName.ValueString(), data.PortAssignments[i].ConnectedDeviceType.ValueString(), data.PortAssignments[i].DataVlanName.ValueString(), data.PortAssignments[i].VoiceVlanName.ValueString(), data.PortAssignments[i].AuthenticateTemplateName.ValueString(), data.PortAssignments[i].SecurityGroupName.ValueString(), data.PortAssignments[i].InterfaceDescription.ValueString()}
+
+ var r gjson.Result
+ res.ForEach(
+ func(_, v gjson.Result) bool {
+ found := false
+ for ik := range keys {
+ if v.Get(keys[ik]).String() == keyValues[ik] {
+ found = true
+ continue
+ }
+ found = false
+ break
+ }
+ if found {
+ r = v
+ return false
+ }
+ return true
+ },
+ )
+ if value := r.Get("fabricId"); value.Exists() && !data.PortAssignments[i].FabricId.IsNull() {
+ data.PortAssignments[i].FabricId = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].FabricId = types.StringNull()
+ }
+ if value := r.Get("networkDeviceId"); value.Exists() && !data.PortAssignments[i].NetworkDeviceId.IsNull() {
+ data.PortAssignments[i].NetworkDeviceId = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].NetworkDeviceId = types.StringNull()
+ }
+ if value := r.Get("interfaceName"); value.Exists() && !data.PortAssignments[i].InterfaceName.IsNull() {
+ data.PortAssignments[i].InterfaceName = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].InterfaceName = types.StringNull()
+ }
+ if value := r.Get("connectedDeviceType"); value.Exists() && !data.PortAssignments[i].ConnectedDeviceType.IsNull() {
+ data.PortAssignments[i].ConnectedDeviceType = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].ConnectedDeviceType = types.StringNull()
+ }
+ if value := r.Get("dataVlanName"); value.Exists() && !data.PortAssignments[i].DataVlanName.IsNull() {
+ data.PortAssignments[i].DataVlanName = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].DataVlanName = types.StringNull()
+ }
+ if value := r.Get("voiceVlanName"); value.Exists() && !data.PortAssignments[i].VoiceVlanName.IsNull() {
+ data.PortAssignments[i].VoiceVlanName = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].VoiceVlanName = types.StringNull()
+ }
+ if value := r.Get("authenticateTemplateName"); value.Exists() && !data.PortAssignments[i].AuthenticateTemplateName.IsNull() {
+ data.PortAssignments[i].AuthenticateTemplateName = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].AuthenticateTemplateName = types.StringNull()
+ }
+ if value := r.Get("securityGroupName"); value.Exists() && !data.PortAssignments[i].SecurityGroupName.IsNull() {
+ data.PortAssignments[i].SecurityGroupName = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].SecurityGroupName = types.StringNull()
+ }
+ if value := r.Get("interfaceDescription"); value.Exists() && !data.PortAssignments[i].InterfaceDescription.IsNull() {
+ data.PortAssignments[i].InterfaceDescription = types.StringValue(value.String())
+ } else {
+ data.PortAssignments[i].InterfaceDescription = types.StringNull()
+ }
+ }
+}
+
+// End of section. //template:end updateFromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin isNull
+func (data *FabricPortAssignment) isNull(ctx context.Context, res gjson.Result) bool {
+ if len(data.PortAssignments) > 0 {
+ return false
+ }
+ return true
+}
+
+// End of section. //template:end isNull
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 6a0da26..2b147ba 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -258,6 +258,7 @@ func (p *CcProvider) Resources(ctx context.Context) []func() resource.Resource {
NewFabricDeviceResource,
NewFabricL2HandoffResource,
NewFabricL3HandoffIPTransitResource,
+ NewFabricPortAssignmentResource,
NewFabricProvisionDeviceResource,
NewFabricSiteResource,
NewFabricVirtualNetworkResource,
@@ -313,6 +314,7 @@ func (p *CcProvider) DataSources(ctx context.Context) []func() datasource.DataSo
NewFabricDeviceDataSource,
NewFabricL2HandoffDataSource,
NewFabricL3HandoffIPTransitDataSource,
+ NewFabricPortAssignmentDataSource,
NewFabricProvisionDeviceDataSource,
NewFabricSiteDataSource,
NewFabricVirtualNetworkDataSource,
diff --git a/internal/provider/resource_catalystcenter_fabric_port_assignment.go b/internal/provider/resource_catalystcenter_fabric_port_assignment.go
new file mode 100644
index 0000000..6956229
--- /dev/null
+++ b/internal/provider/resource_catalystcenter_fabric_port_assignment.go
@@ -0,0 +1,271 @@
+// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "strings"
+
+ "github.com/CiscoDevNet/terraform-provider-catalystcenter/internal/provider/helpers"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "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"
+ cc "github.com/netascode/go-catalystcenter"
+)
+
+// 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 = &FabricPortAssignmentResource{}
+
+func NewFabricPortAssignmentResource() resource.Resource {
+ return &FabricPortAssignmentResource{}
+}
+
+type FabricPortAssignmentResource struct {
+ client *cc.Client
+}
+
+func (r *FabricPortAssignmentResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_fabric_port_assignment"
+}
+
+func (r *FabricPortAssignmentResource) 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("Manages Port Assignments in SD-Access Fabric").String,
+
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ MarkdownDescription: "The id of the object",
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ "fabric_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("ID of the fabric the device is assigned to").String,
+ Optional: true,
+ },
+ "network_device_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Network device ID of the port assignment").String,
+ Required: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ "port_assignments": schema.ListNestedAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("List of port assignments in SD-Access fabric").String,
+ Required: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "fabric_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("ID of the fabric the device is assigned to").String,
+ Required: true,
+ },
+ "network_device_id": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Network device ID of the port assignment").String,
+ Required: true,
+ },
+ "interface_name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Interface name of the port assignment").String,
+ Required: true,
+ },
+ "connected_device_type": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Connected device type of the port assignment").AddStringEnumDescription("USER_DEVICE", "ACCESS_POINT", "TRUNKING_DEVICE", "AUTHENTICATOR_SWITCH", "SUPPLICANT_BASED_EXTENDED_NODE").String,
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("USER_DEVICE", "ACCESS_POINT", "TRUNKING_DEVICE", "AUTHENTICATOR_SWITCH", "SUPPLICANT_BASED_EXTENDED_NODE"),
+ },
+ },
+ "data_vlan_name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Data VLAN name of the port assignment").String,
+ Optional: true,
+ },
+ "voice_vlan_name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Voice VLAN name of the port assignment").String,
+ Optional: true,
+ },
+ "authenticate_template_name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Authenticate template name of the port assignment").AddStringEnumDescription("No Authentication", "Open Authentication", "Closed Authentication", "Low Impact").String,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("No Authentication", "Open Authentication", "Closed Authentication", "Low Impact"),
+ },
+ },
+ "security_group_name": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Security group name of the port assignment").String,
+ Optional: true,
+ },
+ "interface_description": schema.StringAttribute{
+ MarkdownDescription: helpers.NewAttributeDescription("Interface description of the port assignment").String,
+ Optional: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func (r *FabricPortAssignmentResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ r.client = req.ProviderData.(*CcProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin create
+func (r *FabricPortAssignmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var plan FabricPortAssignment
+
+ // Read plan
+ diags := req.Plan.Get(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString()))
+
+ // Create object
+ body := plan.toBody(ctx, FabricPortAssignment{})
+
+ params := ""
+ res, err := r.client.Post(plan.getPath()+params, body)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST), got error: %s, %s", err, res.String()))
+ return
+ }
+ plan.Id = types.StringValue(fmt.Sprint(plan.NetworkDeviceId.ValueString()))
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
+
+ diags = resp.State.Set(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end create
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+func (r *FabricPortAssignmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var state FabricPortAssignment
+
+ // Read state
+ diags := req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String()))
+
+ params := ""
+ params += "?fabricId=" + url.QueryEscape(state.FabricId.ValueString()) + "&networkDeviceId=" + url.QueryEscape(state.NetworkDeviceId.ValueString())
+ res, err := r.client.Get(state.getPath() + params)
+ 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
+ }
+
+ // If every attribute is set to null we are dealing with an import operation and therefore reading all attributes
+ if state.isNull(ctx, res) {
+ state.fromBody(ctx, res)
+ } else {
+ state.updateFromBody(ctx, res)
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString()))
+
+ diags = resp.State.Set(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end read
+
+// Section below is generated&owned by "gen/generator.go". //template:begin update
+func (r *FabricPortAssignmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var plan, state FabricPortAssignment
+
+ // Read plan
+ diags := req.Plan.Get(ctx, &plan)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ // Read state
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))
+
+ 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 *FabricPortAssignmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var state FabricPortAssignment
+
+ // Read state
+ diags := req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
+ params := "?fabricId=" + url.QueryEscape(state.FabricId.ValueString()) + "&networkDeviceId=" + url.QueryEscape(state.NetworkDeviceId.ValueString())
+ res, err := r.client.Delete(state.getPath() + params)
+ 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
+// End of section. //template:end import
diff --git a/internal/provider/resource_catalystcenter_fabric_port_assignment_test.go b/internal/provider/resource_catalystcenter_fabric_port_assignment_test.go
new file mode 100644
index 0000000..03efb76
--- /dev/null
+++ b/internal/provider/resource_catalystcenter_fabric_port_assignment_test.go
@@ -0,0 +1,96 @@
+// 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 TestAccCcFabricPortAssignment(t *testing.T) {
+ if os.Getenv("SDA") == "" {
+ t.Skip("skipping test, set environment variable SDA")
+ }
+ var checks []resource.TestCheckFunc
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.network_device_id", "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"))
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.interface_name", "GigabitEthernet1/0/2"))
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.connected_device_type", "USER_DEVICE"))
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.data_vlan_name", "DATA_VLAN"))
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.voice_vlan_name", "VOICE_VLAN"))
+ checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_port_assignment.test", "port_assignments.0.authenticate_template_name", "No Authentication"))
+
+ var steps []resource.TestStep
+ steps = append(steps, resource.TestStep{
+ Config: testAccCcFabricPortAssignmentConfig_all(),
+ Check: resource.ComposeTestCheckFunc(checks...),
+ })
+
+ 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 testAccCcFabricPortAssignmentConfig_minimum() string {
+ config := `resource "catalystcenter_fabric_port_assignment" "test" {` + "\n"
+ config += ` fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"` + "\n"
+ config += ` port_assignments = [{` + "\n"
+ config += ` fabric_id = catalystcenter_fabric_site.test.id` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"` + "\n"
+ config += ` interface_name = "GigabitEthernet1/0/2"` + "\n"
+ config += ` connected_device_type = "USER_DEVICE"` + "\n"
+ config += ` }]` + "\n"
+ config += `}` + "\n"
+ return config
+}
+
+// End of section. //template:end testAccConfigMinimal
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll
+func testAccCcFabricPortAssignmentConfig_all() string {
+ config := `resource "catalystcenter_fabric_port_assignment" "test" {` + "\n"
+ config += ` fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"` + "\n"
+ config += ` port_assignments = [{` + "\n"
+ config += ` fabric_id = catalystcenter_fabric_site.test.id` + "\n"
+ config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"` + "\n"
+ config += ` interface_name = "GigabitEthernet1/0/2"` + "\n"
+ config += ` connected_device_type = "USER_DEVICE"` + "\n"
+ config += ` data_vlan_name = "DATA_VLAN"` + "\n"
+ config += ` voice_vlan_name = "VOICE_VLAN"` + "\n"
+ config += ` authenticate_template_name = "No Authentication"` + "\n"
+ config += ` }]` + "\n"
+ config += `}` + "\n"
+ return config
+}
+
+// End of section. //template:end testAccConfigAll
diff --git a/templates/guides/changelog.md.tmpl b/templates/guides/changelog.md.tmpl
index 4f8a03b..74f83c3 100644
--- a/templates/guides/changelog.md.tmpl
+++ b/templates/guides/changelog.md.tmpl
@@ -9,6 +9,7 @@ description: |-
## 0.1.11 (unreleased)
+- Add `catalystcenter_fabric_port_assignment` resource and data source
- Add `catalystcenter_wireless_ssid` resource and data source
- Add `catalystcenter_site` data source
- Add `catalystcenter_fabric_vlan_to_ssid` resource and data source