@@ -2,24 +2,28 @@ package devices
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
67 "os"
7- "strconv"
88
99 "github.com/MakeNowJust/heredoc/v2"
1010 "github.com/charmbracelet/log"
1111 "github.com/ctrlplanedev/cli/internal/api"
12- ctrlp "github.com/ctrlplanedev/cli/internal/common"
13- netbox "github.com/netbox-community/go-netbox/v4"
12+ "github.com/ctrlplanedev/cli/internal/common"
1413 "github.com/spf13/cobra"
1514)
1615
17- const pageSize int32 = 100
18-
1916func NewSyncDevicesCmd () * cobra.Command {
2017 var netboxURL string
2118 var netboxToken string
2219 var providerName string
20+ var query string
21+ var siteFilter []string
22+ var roleFilter []string
23+ var statusFilter []string
24+ var statusExcludeFilter []string
25+ var tagFilter []string
26+ var tenantFilter []string
2327
2428 cmd := & cobra.Command {
2529 Use : "devices" ,
@@ -31,9 +35,17 @@ func NewSyncDevicesCmd() *cobra.Command {
3135 ctx := context .Background ()
3236 log .Info ("Syncing Netbox devices into Ctrlplane" )
3337
34- client := netbox .NewAPIClientFor (netboxURL , netboxToken )
38+ filters := deviceFilters {
39+ Query : query ,
40+ Site : siteFilter ,
41+ Role : roleFilter ,
42+ Status : statusFilter ,
43+ StatusExclude : statusExcludeFilter ,
44+ Tag : tagFilter ,
45+ Tenant : tenantFilter ,
46+ }
3547
36- allDevices , err := fetchAllDevices (ctx , client )
48+ allDevices , err := fetchAllDevicesDirect (ctx , netboxURL , netboxToken , filters )
3749 if err != nil {
3850 return fmt .Errorf ("failed to list Netbox devices: %w" , err )
3951 }
@@ -49,111 +61,32 @@ func NewSyncDevicesCmd() *cobra.Command {
4961 providerName = "netbox-devices"
5062 }
5163
52- return ctrlp .UpsertResources (ctx , resources , & providerName )
64+ for _ , resource := range resources {
65+ b , err := json .MarshalIndent (resource , "" , " " )
66+ if err != nil {
67+ fmt .Printf ("error marshaling resource: %v\n " , err )
68+ continue
69+ }
70+ fmt .Println (string (b ))
71+ }
72+
73+ return common .UpsertResources (ctx , resources , & providerName )
5374 },
5475 }
5576
5677 cmd .Flags ().StringVar (& netboxURL , "netbox-url" , os .Getenv ("NETBOX_URL" ), "Netbox instance URL" )
5778 cmd .Flags ().StringVar (& netboxToken , "netbox-token" , os .Getenv ("NETBOX_TOKEN" ), "Netbox API token" )
5879 cmd .Flags ().StringVarP (& providerName , "provider" , "p" , "" , "Resource provider name (default: netbox-devices)" )
80+ cmd .Flags ().StringVar (& query , "q" , "" , "Search query for Netbox devices" )
81+ cmd .Flags ().StringSliceVar (& siteFilter , "site" , nil , "Filter by Netbox site slug/name (repeatable)" )
82+ cmd .Flags ().StringSliceVar (& roleFilter , "role" , nil , "Filter by Netbox device role slug/name (repeatable)" )
83+ cmd .Flags ().StringSliceVar (& statusFilter , "status" , nil , "Filter by Netbox status (repeatable)" )
84+ cmd .Flags ().StringSliceVar (& statusExcludeFilter , "status-n" , nil , "Exclude Netbox status values (repeatable)" )
85+ cmd .Flags ().StringSliceVar (& tagFilter , "tag" , nil , "Filter by Netbox tag slug (repeatable)" )
86+ cmd .Flags ().StringSliceVar (& tenantFilter , "tenant" , nil , "Filter by Netbox tenant slug/name (repeatable)" )
5987
6088 cmd .MarkFlagRequired ("netbox-url" )
6189 cmd .MarkFlagRequired ("netbox-token" )
6290
6391 return cmd
6492}
65-
66- func fetchAllDevices (ctx context.Context , client * netbox.APIClient ) ([]netbox.DeviceWithConfigContext , error ) {
67- var all []netbox.DeviceWithConfigContext
68- var offset int32
69- page := 1
70-
71- for {
72- log .Info ("Fetching Netbox devices page" , "page" , page , "offset" , offset , "limit" , pageSize )
73- res , _ , err := client .DcimAPI .
74- DcimDevicesList (ctx ).
75- Limit (pageSize ).
76- Offset (offset ).
77- Execute ()
78- if err != nil {
79- log .Error (err , "Failed to fetch Netbox devices page" , "page" , page , "offset" , offset )
80- return nil , err
81- }
82-
83- log .Info ("Fetched devices from Netbox page" , "page" , page , "count" , len (res .Results ), "total" , res .Count )
84- all = append (all , res .Results ... )
85-
86- if int32 (len (all )) >= res .Count {
87- log .Info ("All Netbox devices fetched" , "total_count" , len (all ))
88- break
89- }
90- offset += pageSize
91- page ++
92- }
93-
94- return all , nil
95- }
96-
97- func mapDevice (device netbox.DeviceWithConfigContext ) api.ResourceProviderResource {
98- metadata := map [string ]string {}
99-
100- metadata ["netbox/id" ] = strconv .Itoa (int (device .Id ))
101- metadata ["netbox/site" ] = device .GetSite ().Name
102-
103- if device .Status != nil {
104- metadata ["netbox/status" ] = string (device .Status .GetValue ())
105- }
106- if rack , ok := device .GetRackOk (); ok && rack != nil {
107- metadata ["netbox/rack" ] = rack .GetName ()
108- }
109- if tenant , ok := device .GetTenantOk (); ok && tenant != nil {
110- metadata ["netbox/tenant" ] = tenant .GetName ()
111- }
112- if role := device .Role ; role .Name != "" {
113- metadata ["netbox/role" ] = role .Name
114- }
115- if platform , ok := device .GetPlatformOk (); ok && platform != nil {
116- metadata ["netbox/platform" ] = platform .GetName ()
117- }
118-
119- for _ , tag := range device .Tags {
120- metadata [fmt .Sprintf ("netbox/tag/%s" , tag .Slug )] = "true"
121- }
122-
123- site := device .GetSite ()
124- config := map [string ]any {
125- "id" : device .Id ,
126- "name" : device .GetName (),
127- "device_type" : device .DeviceType .GetDisplay (),
128- "role" : device .Role .GetName (),
129- "site" : map [string ]any {
130- "id" : site .Id ,
131- "url" : site .Url ,
132- "slug" : site .Slug ,
133- "name" : site .Name ,
134- },
135- }
136- if device .Serial != nil {
137- config ["serial" ] = * device .Serial
138- }
139- if pip , ok := device .GetPrimaryIpOk (); ok && pip != nil {
140- config ["primaryIp" ] = pip .GetAddress ()
141- }
142- if platform , ok := device .GetPlatformOk (); ok && platform != nil {
143- config ["platform" ] = platform .GetName ()
144- }
145-
146- name := device .GetName ()
147- if name == "" {
148- name = device .Display
149- }
150-
151- return api.ResourceProviderResource {
152- Version : "netbox/device/v1" ,
153- Kind : "Device" ,
154- Name : name ,
155- Identifier : strconv .Itoa (int (device .Id )),
156- Config : config ,
157- Metadata : metadata ,
158- }
159- }
0 commit comments