Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #159

Closed
wants to merge 6 commits into from
Closed

Dev #159

Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fabric_port_assingment manual changes
kuba-mazurkiewicz committed Dec 10, 2024
commit e590c715daeaef636e5f6bf597eb1bcafcfb98f8
3 changes: 2 additions & 1 deletion docs/data-sources/fabric_port_assignment.md
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ data "catalystcenter_fabric_port_assignment" "example" {
### 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))
- `port_assignments` (Attributes Set) List of port assignments in SD-Access fabric (see [below for nested schema](#nestedatt--port_assignments))

<a id="nestedatt--port_assignments"></a>
### Nested Schema for `port_assignments`
@@ -41,6 +41,7 @@ Read-Only:
- `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
- `id` (String) ID of the port assignment
- `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
4 changes: 3 additions & 1 deletion docs/resources/fabric_port_assignment.md
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ resource "catalystcenter_fabric_port_assignment" "example" {
network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
port_assignments = [
{
id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
fabric_id = "c4b85bb2-ce3f-4db9-a32b-e439a388ac2f"
network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
interface_name = "GigabitEthernet1/0/2"
@@ -36,7 +37,7 @@ resource "catalystcenter_fabric_port_assignment" "example" {
### 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))
- `port_assignments` (Attributes Set) List of port assignments in SD-Access fabric (see [below for nested schema](#nestedatt--port_assignments))

### Optional

@@ -62,6 +63,7 @@ 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
- `id` (String) ID 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
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ resource "catalystcenter_fabric_port_assignment" "example" {
network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"
port_assignments = [
{
id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
fabric_id = "c4b85bb2-ce3f-4db9-a32b-e439a388ac2f"
network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"
interface_name = "GigabitEthernet1/0/2"
13 changes: 7 additions & 6 deletions gen/definitions/fabric_port_assignment.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
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
@@ -32,28 +31,30 @@ attributes:
description: Network device ID of the port assignment
example: 5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b
- tf_name: port_assignments
type: List
type: Set
response_data_path: response
mandatory: true
description: List of port assignments in SD-Access fabric
attributes:
- model_name: id
type: String
computed: true
description: ID of the port assignment
example: 5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1
- 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
id: true
type: String
description: Interface name of the port assignment
example: GigabitEthernet1/0/2
Original file line number Diff line number Diff line change
@@ -69,11 +69,15 @@ func (d *FabricPortAssignmentDataSource) Schema(ctx context.Context, req datasou
MarkdownDescription: "Network device ID of the port assignment",
Required: true,
},
"port_assignments": schema.ListNestedAttribute{
"port_assignments": schema.SetNestedAttribute{
MarkdownDescription: "List of port assignments in SD-Access fabric",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "ID of the port assignment",
Computed: true,
},
"fabric_id": schema.StringAttribute{
MarkdownDescription: "ID of the fabric the device is assigned to",
Computed: true,
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ func TestAccDataSourceCcFabricPortAssignment(t *testing.T) {
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.id", "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"))
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"))
@@ -62,6 +63,7 @@ func testAccDataSourceCcFabricPortAssignmentConfig() string {
config += ` fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"` + "\n"
config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"` + "\n"
config += ` port_assignments = [{` + "\n"
config += ` id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"` + "\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"
18 changes: 16 additions & 2 deletions internal/provider/model_catalystcenter_fabric_port_assignment.go
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@ type FabricPortAssignment struct {
}

type FabricPortAssignmentPortAssignments struct {
Id types.String `tfsdk:"id"`
FabricId types.String `tfsdk:"fabric_id"`
NetworkDeviceId types.String `tfsdk:"network_device_id"`
InterfaceName types.String `tfsdk:"interface_name"`
@@ -79,6 +80,9 @@ func (data FabricPortAssignment) toBody(ctx context.Context, state FabricPortAss
body, _ = sjson.Set(body, "", []interface{}{})
for _, item := range data.PortAssignments {
itemBody := ""
if !item.Id.IsNull() {
itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString())
}
if !item.FabricId.IsNull() {
itemBody, _ = sjson.Set(itemBody, "fabricId", item.FabricId.ValueString())
}
@@ -128,6 +132,11 @@ func (data *FabricPortAssignment) fromBody(ctx context.Context, res gjson.Result
data.PortAssignments = make([]FabricPortAssignmentPortAssignments, 0)
value.ForEach(func(k, v gjson.Result) bool {
item := FabricPortAssignmentPortAssignments{}
if cValue := v.Get("id"); cValue.Exists() {
item.Id = types.StringValue(cValue.String())
} else {
item.Id = types.StringNull()
}
if cValue := v.Get("fabricId"); cValue.Exists() {
item.FabricId = types.StringValue(cValue.String())
} else {
@@ -186,8 +195,8 @@ func (data *FabricPortAssignment) updateFromBody(ctx context.Context, res gjson.

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()}
keys := [...]string{"interfaceName"}
keyValues := [...]string{data.PortAssignments[i].InterfaceName.ValueString()}

var r gjson.Result
res.ForEach(
@@ -208,6 +217,11 @@ func (data *FabricPortAssignment) updateFromBody(ctx context.Context, res gjson.
return true
},
)
if value := r.Get("id"); value.Exists() && !data.PortAssignments[i].Id.IsNull() {
data.PortAssignments[i].Id = types.StringValue(value.String())
} else {
data.PortAssignments[i].Id = types.StringNull()
}
if value := r.Get("fabricId"); value.Exists() && !data.PortAssignments[i].FabricId.IsNull() {
data.PortAssignments[i].FabricId = types.StringValue(value.String())
} else {
121 changes: 114 additions & 7 deletions internal/provider/resource_catalystcenter_fabric_port_assignment.go
Original file line number Diff line number Diff line change
@@ -79,11 +79,19 @@ func (r *FabricPortAssignmentResource) Schema(ctx context.Context, req resource.
stringplanmodifier.RequiresReplace(),
},
},
"port_assignments": schema.ListNestedAttribute{
"port_assignments": schema.SetNestedAttribute{
MarkdownDescription: helpers.NewAttributeDescription("List of port assignments in SD-Access fabric").String,
Required: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: helpers.NewAttributeDescription("ID of the port assignment").String,
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"fabric_id": schema.StringAttribute{
MarkdownDescription: helpers.NewAttributeDescription("ID of the fabric the device is assigned to").String,
Required: true,
@@ -143,7 +151,6 @@ func (r *FabricPortAssignmentResource) Configure(_ context.Context, req resource

// 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

@@ -172,6 +179,31 @@ func (r *FabricPortAssignmentResource) Create(ctx context.Context, req resource.
return
}
}
params = ""
params += "?fabricId=" + url.QueryEscape(plan.FabricId.ValueString()) + "&networkDeviceId=" + url.QueryEscape(plan.NetworkDeviceId.ValueString())
res, err = r.client.Get(plan.getPath() + params)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
return
}

// Map response to portAssignments
responseArray := res.Get("response").Array()
portAssignments := make([]FabricPortAssignmentPortAssignments, len(plan.PortAssignments))
copy(portAssignments, plan.PortAssignments) // Make a copy to update values
for i, port := range portAssignments {
for _, respPort := range responseArray {
if respPort.Get("interfaceName").String() == port.InterfaceName.ValueString() {
port.Id = types.StringValue(respPort.Get("id").String())
break
}
}
portAssignments[i] = port
}

// Update the plan with mapped portAssignments
plan.PortAssignments = portAssignments

plan.Id = types.StringValue(fmt.Sprint(plan.NetworkDeviceId.ValueString()))

tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
@@ -180,8 +212,6 @@ func (r *FabricPortAssignmentResource) Create(ctx context.Context, req resource.
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
@@ -221,7 +251,6 @@ func (r *FabricPortAssignmentResource) Read(ctx context.Context, req resource.Re

// 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

@@ -240,14 +269,92 @@ func (r *FabricPortAssignmentResource) Update(ctx context.Context, req resource.

tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))

// Identify removed interfaces
stateAssignments := make(map[string]FabricPortAssignmentPortAssignments)
for _, sa := range state.PortAssignments {
stateAssignments[sa.InterfaceName.ValueString()] = sa
}

planAssignments := make(map[string]FabricPortAssignmentPortAssignments)
for _, pa := range plan.PortAssignments {
planAssignments[pa.InterfaceName.ValueString()] = pa
}

// Find interfaces to delete
for interfaceName, stateAssignment := range stateAssignments {
if _, exists := planAssignments[interfaceName]; !exists {
// Interface exists in state but not in plan, delete it
_, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(stateAssignment.Id.ValueString()))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete port assignment for interface %s, got error: %s", interfaceName, err))
} else {
tflog.Debug(ctx, fmt.Sprintf("Deleted port assignment for interface: %s", interfaceName))
}
}
}

// Find interfaces to create
for interfaceName, planAssignment := range planAssignments {
if _, exists := stateAssignments[interfaceName]; !exists {
// Create a temporary FabricPortAssignment for the current interface
singlePortAssignment := FabricPortAssignment{
FabricId: plan.FabricId,
NetworkDeviceId: plan.NetworkDeviceId,
PortAssignments: []FabricPortAssignmentPortAssignments{planAssignment}, // Filtered for the current interface
}

// Generate the body using the existing toBody function
body := singlePortAssignment.toBody(ctx, state)

// Send the body as the POST request
_, err := r.client.Post(state.getPath(), body)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to create port assignment for interface %s, got error: %s", interfaceName, err))
} else {
tflog.Debug(ctx, fmt.Sprintf("Created port assignment for interface: %s", interfaceName))

// Get the existing ID for the given interface
params := "?fabricId=" + url.QueryEscape(plan.FabricId.ValueString()) + "&networkDeviceId=" + url.QueryEscape(plan.NetworkDeviceId.ValueString())

res, err := r.client.Get(plan.getPath() + params)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
return
}

// Log the full response for debugging purposes
tflog.Debug(ctx, fmt.Sprintf("API response: %s", res.String()))

// Check if the ID is present in the response
planAssignment.Id = types.StringValue(res.Get("response.#(interfaceName==\"" + planAssignment.InterfaceName.ValueString() + "\").id").String())

// Update the assignment in the plan
for i := range plan.PortAssignments {
if plan.PortAssignments[i].InterfaceName.ValueString() == planAssignment.InterfaceName.ValueString() {
plan.PortAssignments[i] = planAssignment
break
}
}
}
}
}

tflog.Debug(ctx, fmt.Sprintf("Plan Port Assignments: %+v", plan.PortAssignments))

body := plan.toBody(ctx, state)
params := ""
res, err := r.client.Put(plan.getPath()+params, body)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
return
}

tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString()))

diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

// End of section. //template:end update

// Section below is generated&owned by "gen/generator.go". //template:begin delete
func (r *FabricPortAssignmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state FabricPortAssignment
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ func TestAccCcFabricPortAssignment(t *testing.T) {
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.id", "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"))
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"))
@@ -81,6 +82,7 @@ func testAccCcFabricPortAssignmentConfig_all() string {
config += ` fabric_id = "e02d9911-b0a7-435b-bb46-079d877d7b3e"` + "\n"
config += ` network_device_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b"` + "\n"
config += ` port_assignments = [{` + "\n"
config += ` id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1"` + "\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"