Skip to content

Commit 1af2d08

Browse files
Add import devices in bulk - resolves enhancement #55 (#103)
1 parent 37789d4 commit 1af2d08

File tree

10 files changed

+578
-0
lines changed

10 files changed

+578
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## 0.1.10 (unreleased)
22

3+
- Add `pnp_import_devices` resource
34
- Add `fabric_device` resource and data source, this resource now only works with Catalyst Center version 2.3.7.5+ `/sda/fabricDevices`
45
- Add `fabric_l3_handoff_ip_transit` resource and data source
56
- Add `transitPeerNetworkId` as `id` to `transit_peer_network` resource

docs/guides/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ description: |-
99

1010
## 0.1.10 (unreleased)
1111

12+
- Add `pnp_import_devices` resource
1213
- Add `fabric_device` resource and data source, this resource now only works with Catalyst Center version 2.3.7.5+ `/sda/fabricDevices`
1314
- Add `fabric_l3_handoff_ip_transit` resource and data source
1415
- Add `transitPeerNetworkId` as `id` to `transit_peer_network` resource

docs/resources/pnp_import_devices.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "catalystcenter_pnp_import_devices Resource - terraform-provider-catalystcenter"
4+
subcategory: "Plug and Play"
5+
description: |-
6+
This resource adds devices to PNP in bulk. Every time this resource is created or re-created, the Catalyst Center considers adding new devices to PNP. When this resource is destroyed or updated or refreshed, no actions are done either on CatalystCenter or on devices.
7+
---
8+
9+
# catalystcenter_pnp_import_devices (Resource)
10+
11+
This resource adds devices to PNP in bulk. Every time this resource is created or re-created, the Catalyst Center considers adding new devices to PNP. When this resource is destroyed or updated or refreshed, no actions are done either on CatalystCenter or on devices.
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "catalystcenter_pnp_import_devices" "example" {
17+
devices = [
18+
{
19+
serial_number = "FOC12345678"
20+
stack = false
21+
pid = "C9300-24P"
22+
hostname = "switch1"
23+
}
24+
]
25+
}
26+
```
27+
28+
<!-- schema generated by tfplugindocs -->
29+
## Schema
30+
31+
### Required
32+
33+
- `devices` (Attributes List) List of devices to add (see [below for nested schema](#nestedatt--devices))
34+
35+
### Read-Only
36+
37+
- `id` (String) The id of the object
38+
39+
<a id="nestedatt--devices"></a>
40+
### Nested Schema for `devices`
41+
42+
Optional:
43+
44+
- `hostname` (String) Device hostname
45+
- `pid` (String) Device product ID
46+
- `serial_number` (String) Device serial number
47+
- `stack` (Boolean) Device is a stacked switch
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
resource "catalystcenter_pnp_import_devices" "example" {
2+
devices = [
3+
{
4+
serial_number = "FOC12345678"
5+
stack = false
6+
pid = "C9300-24P"
7+
hostname = "switch1"
8+
}
9+
]
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
name: PnP Import Devices
3+
rest_endpoint: /dna/intent/api/v1/onboarding/pnp-device/import
4+
res_description: 'This resource adds devices to PNP in bulk.
5+
Every time this resource is created or re-created, the Catalyst Center considers adding new devices to PNP.
6+
When this resource is destroyed or updated or refreshed, no actions are done either on CatalystCenter or on devices.'
7+
no_data_source: true
8+
no_read: true
9+
no_delete: true
10+
no_import: true
11+
no_update: true
12+
id_path: id
13+
root_list: true
14+
doc_category: Plug and Play
15+
test_tags: [PNP]
16+
attributes:
17+
- tf_name: devices
18+
type: List
19+
mandatory: true
20+
description: List of devices to add
21+
attributes:
22+
- model_name: serialNumber
23+
data_path: deviceInfo
24+
type: String
25+
description: Device serial number
26+
example: FOC12345678
27+
- model_name: stack
28+
data_path: deviceInfo
29+
type: Bool
30+
description: Device is a stacked switch
31+
example: false
32+
- model_name: pid
33+
data_path: deviceInfo
34+
type: String
35+
description: Device product ID
36+
example: C9300-24P
37+
- model_name: hostname
38+
data_path: deviceInfo
39+
type: String
40+
description: Device hostname
41+
example: switch1
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
2+
// All rights reserved.
3+
//
4+
// Licensed under the Mozilla Public License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://mozilla.org/MPL/2.0/
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
// SPDX-License-Identifier: MPL-2.0
17+
18+
package provider
19+
20+
// Section below is generated&owned by "gen/generator.go". //template:begin imports
21+
import (
22+
"context"
23+
"strconv"
24+
25+
"github.com/hashicorp/terraform-plugin-framework/types"
26+
"github.com/tidwall/gjson"
27+
"github.com/tidwall/sjson"
28+
)
29+
30+
// End of section. //template:end imports
31+
32+
// Section below is generated&owned by "gen/generator.go". //template:begin types
33+
type PnPImportDevices struct {
34+
Id types.String `tfsdk:"id"`
35+
Devices []PnPImportDevicesDevices `tfsdk:"devices"`
36+
}
37+
38+
type PnPImportDevicesDevices struct {
39+
SerialNumber types.String `tfsdk:"serial_number"`
40+
Stack types.Bool `tfsdk:"stack"`
41+
Pid types.String `tfsdk:"pid"`
42+
Hostname types.String `tfsdk:"hostname"`
43+
}
44+
45+
// End of section. //template:end types
46+
47+
// Section below is generated&owned by "gen/generator.go". //template:begin getPath
48+
func (data PnPImportDevices) getPath() string {
49+
return "/dna/intent/api/v1/onboarding/pnp-device/import"
50+
}
51+
52+
// End of section. //template:end getPath
53+
54+
// Section below is generated&owned by "gen/generator.go". //template:begin getPathDelete
55+
56+
// End of section. //template:end getPathDelete
57+
58+
// Section below is generated&owned by "gen/generator.go". //template:begin toBody
59+
func (data PnPImportDevices) toBody(ctx context.Context, state PnPImportDevices) string {
60+
body := "[]"
61+
put := false
62+
if state.Id.ValueString() != "" {
63+
put = true
64+
}
65+
_ = put
66+
if len(data.Devices) > 0 {
67+
body, _ = sjson.Set(body, "", []interface{}{})
68+
for _, item := range data.Devices {
69+
itemBody := ""
70+
if !item.SerialNumber.IsNull() {
71+
itemBody, _ = sjson.Set(itemBody, "deviceInfo.serialNumber", item.SerialNumber.ValueString())
72+
}
73+
if !item.Stack.IsNull() {
74+
itemBody, _ = sjson.Set(itemBody, "deviceInfo.stack", item.Stack.ValueBool())
75+
}
76+
if !item.Pid.IsNull() {
77+
itemBody, _ = sjson.Set(itemBody, "deviceInfo.pid", item.Pid.ValueString())
78+
}
79+
if !item.Hostname.IsNull() {
80+
itemBody, _ = sjson.Set(itemBody, "deviceInfo.hostname", item.Hostname.ValueString())
81+
}
82+
body, _ = sjson.SetRaw(body, "-1", itemBody)
83+
}
84+
}
85+
return body
86+
}
87+
88+
// End of section. //template:end toBody
89+
90+
// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
91+
func (data *PnPImportDevices) fromBody(ctx context.Context, res gjson.Result) {
92+
if value := res; value.Exists() && len(value.Array()) > 0 {
93+
data.Devices = make([]PnPImportDevicesDevices, 0)
94+
value.ForEach(func(k, v gjson.Result) bool {
95+
item := PnPImportDevicesDevices{}
96+
if cValue := v.Get("deviceInfo.serialNumber"); cValue.Exists() {
97+
item.SerialNumber = types.StringValue(cValue.String())
98+
} else {
99+
item.SerialNumber = types.StringNull()
100+
}
101+
if cValue := v.Get("deviceInfo.stack"); cValue.Exists() {
102+
item.Stack = types.BoolValue(cValue.Bool())
103+
} else {
104+
item.Stack = types.BoolNull()
105+
}
106+
if cValue := v.Get("deviceInfo.pid"); cValue.Exists() {
107+
item.Pid = types.StringValue(cValue.String())
108+
} else {
109+
item.Pid = types.StringNull()
110+
}
111+
if cValue := v.Get("deviceInfo.hostname"); cValue.Exists() {
112+
item.Hostname = types.StringValue(cValue.String())
113+
} else {
114+
item.Hostname = types.StringNull()
115+
}
116+
data.Devices = append(data.Devices, item)
117+
return true
118+
})
119+
}
120+
}
121+
122+
// End of section. //template:end fromBody
123+
124+
// Section below is generated&owned by "gen/generator.go". //template:begin updateFromBody
125+
func (data *PnPImportDevices) updateFromBody(ctx context.Context, res gjson.Result) {
126+
for i := range data.Devices {
127+
keys := [...]string{"deviceInfo.serialNumber", "deviceInfo.stack", "deviceInfo.pid", "deviceInfo.hostname"}
128+
keyValues := [...]string{data.Devices[i].SerialNumber.ValueString(), strconv.FormatBool(data.Devices[i].Stack.ValueBool()), data.Devices[i].Pid.ValueString(), data.Devices[i].Hostname.ValueString()}
129+
130+
var r gjson.Result
131+
res.ForEach(
132+
func(_, v gjson.Result) bool {
133+
found := false
134+
for ik := range keys {
135+
if v.Get(keys[ik]).String() == keyValues[ik] {
136+
found = true
137+
continue
138+
}
139+
found = false
140+
break
141+
}
142+
if found {
143+
r = v
144+
return false
145+
}
146+
return true
147+
},
148+
)
149+
if value := r.Get("deviceInfo.serialNumber"); value.Exists() && !data.Devices[i].SerialNumber.IsNull() {
150+
data.Devices[i].SerialNumber = types.StringValue(value.String())
151+
} else {
152+
data.Devices[i].SerialNumber = types.StringNull()
153+
}
154+
if value := r.Get("deviceInfo.stack"); value.Exists() && !data.Devices[i].Stack.IsNull() {
155+
data.Devices[i].Stack = types.BoolValue(value.Bool())
156+
} else {
157+
data.Devices[i].Stack = types.BoolNull()
158+
}
159+
if value := r.Get("deviceInfo.pid"); value.Exists() && !data.Devices[i].Pid.IsNull() {
160+
data.Devices[i].Pid = types.StringValue(value.String())
161+
} else {
162+
data.Devices[i].Pid = types.StringNull()
163+
}
164+
if value := r.Get("deviceInfo.hostname"); value.Exists() && !data.Devices[i].Hostname.IsNull() {
165+
data.Devices[i].Hostname = types.StringValue(value.String())
166+
} else {
167+
data.Devices[i].Hostname = types.StringNull()
168+
}
169+
}
170+
}
171+
172+
// End of section. //template:end updateFromBody
173+
174+
// Section below is generated&owned by "gen/generator.go". //template:begin isNull
175+
func (data *PnPImportDevices) isNull(ctx context.Context, res gjson.Result) bool {
176+
if len(data.Devices) > 0 {
177+
return false
178+
}
179+
return true
180+
}
181+
182+
// End of section. //template:end isNull

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ func (p *CcProvider) Resources(ctx context.Context) []func() resource.Resource {
270270
NewPNPConfigPreviewResource,
271271
NewPnPDeviceResource,
272272
NewPnPDeviceClaimSiteResource,
273+
NewPnPImportDevicesResource,
273274
NewProjectResource,
274275
NewRoleResource,
275276
NewSPProfileResource,

0 commit comments

Comments
 (0)