diff --git a/plugins/NetBox/v1/dataStreams/circuits.json b/plugins/NetBox/v1/dataStreams/circuits.json index 5e4cce84..fbd5b50b 100644 --- a/plugins/NetBox/v1/dataStreams/circuits.json +++ b/plugins/NetBox/v1/dataStreams/circuits.json @@ -13,7 +13,15 @@ "getArgs": [ { "key": "fields", - "value": "id,cid,display,display_url,provider,provider_account,type,status,tenant,install_date,termination_date,commit_rate,description,termination_a,termination_z,created,last_updated,custom_fields" + "value": "id,cid,display,display_url,provider,provider_account,type,status,tenant,install_date,termination_date,commit_rate,description,termination_a,termination_z,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof circuit !== 'undefined' && circuit && circuit.length) ? circuit.map(o => [].concat(o.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -40,6 +48,34 @@ "expandInnerObjects": true }, "matches": "none", + "ui": [ + { + "type": "objects", + "name": "circuit", + "label": "Circuit(s) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Circuit" + ] + } + } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } + } + ], "metadata": [ { "name": "id", @@ -127,6 +163,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/devices.json b/plugins/NetBox/v1/dataStreams/devices.json index b51378cb..27727389 100644 --- a/plugins/NetBox/v1/dataStreams/devices.json +++ b/plugins/NetBox/v1/dataStreams/devices.json @@ -13,7 +13,11 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,status,role,device_type,platform,site,location,rack,position,face,serial,asset_tag,tenant,primary_ip,oob_ip,cluster,parent_device,description,created,last_updated,custom_fields" + "value": "id,display,display_url,status,role,device_type,platform,site,location,rack,position,face,serial,asset_tag,tenant,primary_ip,oob_ip,cluster,parent_device,description,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof device !== 'undefined' && device && device.length) ? device.map(o => [].concat(o.rawId)[0]) : null }}" }, { "key": "site_id", @@ -26,6 +30,10 @@ { "key": "role", "value": "{{ (typeof role !== 'undefined' && role && role.length) ? [].concat(role).flatMap(r => (r && typeof r === 'object') ? [r.value] : String(r).split(',')).map(r => String(r).trim()).filter(Boolean) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -53,6 +61,19 @@ }, "matches": "none", "ui": [ + { + "type": "objects", + "name": "device", + "label": "Device(s) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Device" + ] + } + } + }, { "type": "objects", "name": "site", @@ -90,6 +111,19 @@ "dataStreamName": "deviceRoles", "dataSourceConfig": {} } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -260,6 +294,21 @@ "computed": true, "valueExpression": "{{ typeof $['last_updated'] === 'string' && $['last_updated'] ? Math.floor((Date.now() - new Date($['last_updated']).getTime()) / 86400000) : null }}" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/ipAddresses.json b/plugins/NetBox/v1/dataStreams/ipAddresses.json index 58e6779f..754da6d3 100644 --- a/plugins/NetBox/v1/dataStreams/ipAddresses.json +++ b/plugins/NetBox/v1/dataStreams/ipAddresses.json @@ -13,7 +13,7 @@ "getArgs": [ { "key": "fields", - "value": "id,address,display,display_url,family,vrf,tenant,status,role,assigned_object_id,assigned_object,dns_name,description,created,last_updated,custom_fields" + "value": "id,address,display,display_url,family,vrf,tenant,status,role,assigned_object_id,assigned_object,dns_name,description,created,last_updated,tags,custom_fields" }, { "key": "assigned", @@ -38,6 +38,10 @@ { "key": "virtual_machine_id", "value": "{{ (typeof virtualMachine !== 'undefined' && virtualMachine && virtualMachine.length) ? virtualMachine.map(o => [].concat(o.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -146,6 +150,19 @@ "label": "SLAAC" } ] + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -258,6 +275,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/powerFeeds.json b/plugins/NetBox/v1/dataStreams/powerFeeds.json index 6f3bf107..28209200 100644 --- a/plugins/NetBox/v1/dataStreams/powerFeeds.json +++ b/plugins/NetBox/v1/dataStreams/powerFeeds.json @@ -17,7 +17,7 @@ } ], "postBody": { - "query": "query PowerFeeds($offset: Int = 0) { power_feed_list(pagination: { offset: $offset, limit: 500 }{{ (typeof site !== 'undefined' && site && site.length) ? ', filters: { power_panel: { site: { id: { in_list: [' + site.map(s => Number([].concat(s.rawId)[0])).join(', ') + '] } } } }' : '' }}) { id name description status type supply phase voltage amperage max_utilization available_power mark_connected cable { id } tenant { name } rack { id name } power_panel { id name site { id name } } created last_updated custom_field_data } }" + "query": "query PowerFeeds($offset: Int = 0) { power_feed_list(pagination: { offset: $offset, limit: 500 }{{ (typeof site !== 'undefined' && site && site.length) ? ', filters: { power_panel: { site: { id: { in_list: [' + site.map(s => Number([].concat(s.rawId)[0])).join(', ') + '] } } } }' : '' }}) { id name description status type supply phase voltage amperage max_utilization available_power mark_connected cable { id } tenant { name } rack { id name } power_panel { id name site { id name } } created last_updated tags { name slug display } custom_field_data } }" }, "paging": { "mode": "offset", @@ -54,6 +54,19 @@ ] } } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -192,6 +205,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "rack.id", "visible": false diff --git a/plugins/NetBox/v1/dataStreams/prefixes.json b/plugins/NetBox/v1/dataStreams/prefixes.json index ef588814..fa36bd56 100644 --- a/plugins/NetBox/v1/dataStreams/prefixes.json +++ b/plugins/NetBox/v1/dataStreams/prefixes.json @@ -13,11 +13,19 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,prefix,family,vrf,scope_type,scope,status,role,tenant,vlan,is_pool,mark_utilized,_depth,children,description,created,last_updated,custom_fields" + "value": "id,display,display_url,prefix,family,vrf,scope_type,scope,status,role,tenant,vlan,is_pool,mark_utilized,_depth,children,description,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof prefix !== 'undefined' && prefix && prefix.length) ? prefix.map(o => [].concat(o.rawId)[0]) : null }}" }, { "key": "site_id", "value": "{{ (typeof site !== 'undefined' && site && site.length) ? site.map(s => [].concat(s.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -45,6 +53,19 @@ }, "matches": "none", "ui": [ + { + "type": "objects", + "name": "prefix", + "label": "Prefix(es) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Prefix" + ] + } + } + }, { "type": "objects", "name": "site", @@ -57,6 +78,19 @@ ] } } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -152,6 +186,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/racks.json b/plugins/NetBox/v1/dataStreams/racks.json index 35556efd..02f29c76 100644 --- a/plugins/NetBox/v1/dataStreams/racks.json +++ b/plugins/NetBox/v1/dataStreams/racks.json @@ -13,11 +13,19 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,site,location,status,role,tenant,facility_id,serial,asset_tag,u_height,starting_unit,form_factor,device_count,powerfeed_count,description,created,last_updated,custom_fields" + "value": "id,display,display_url,site,location,status,role,tenant,facility_id,serial,asset_tag,u_height,starting_unit,form_factor,device_count,powerfeed_count,description,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof rack !== 'undefined' && rack && rack.length) ? rack.map(o => [].concat(o.rawId)[0]) : null }}" }, { "key": "site_id", "value": "{{ (typeof site !== 'undefined' && site && site.length) ? site.map(s => [].concat(s.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -45,6 +53,19 @@ }, "matches": "none", "ui": [ + { + "type": "objects", + "name": "rack", + "label": "Rack(s) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Rack" + ] + } + } + }, { "type": "objects", "name": "site", @@ -57,6 +78,19 @@ ] } } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -158,6 +192,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/scripts/powerFeeds.js b/plugins/NetBox/v1/dataStreams/scripts/powerFeeds.js index 8edb8b77..0d8a501c 100644 --- a/plugins/NetBox/v1/dataStreams/scripts/powerFeeds.js +++ b/plugins/NetBox/v1/dataStreams/scripts/powerFeeds.js @@ -3,4 +3,13 @@ if (data && data.errors && data.errors.length) { throw new Error(data.errors.map((e) => e.message).join("; ")); } -result = (data && data.data && data.data.power_feed_list) || []; +// NetBox GraphQL can't require several tags at once (nested AND matches nothing), so the Tag(s) filter is applied +// here to keep the REST streams' "has all selected tags" behaviour. Paging counts the raw list, so this is safe. +const tagSlugs = [].concat((context.config && context.config.tag) || []) + .flatMap((t) => (t && typeof t === "object" ? [t.value] : String(t).split(","))) + .map((t) => String(t).trim()) + .filter(Boolean); + +result = ((data && data.data && data.data.power_feed_list) || []).filter((feed) => + tagSlugs.every((slug) => (feed.tags || []).some((t) => t.slug === slug)), +); diff --git a/plugins/NetBox/v1/dataStreams/scripts/tags.js b/plugins/NetBox/v1/dataStreams/scripts/tags.js new file mode 100644 index 00000000..73dec329 --- /dev/null +++ b/plugins/NetBox/v1/dataStreams/scripts/tags.js @@ -0,0 +1,4 @@ +result = ((data && data.results) || []).map((r) => ({ + label: r.name, + value: r.slug, +})); diff --git a/plugins/NetBox/v1/dataStreams/sites.json b/plugins/NetBox/v1/dataStreams/sites.json index a4afc14f..dc7cda51 100644 --- a/plugins/NetBox/v1/dataStreams/sites.json +++ b/plugins/NetBox/v1/dataStreams/sites.json @@ -13,7 +13,15 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,status,region,group,tenant,facility,time_zone,description,physical_address,latitude,longitude,device_count,rack_count,prefix_count,vlan_count,circuit_count,virtualmachine_count,created,last_updated,custom_fields" + "value": "id,display,display_url,status,region,group,tenant,facility,time_zone,description,physical_address,latitude,longitude,device_count,rack_count,prefix_count,vlan_count,circuit_count,virtualmachine_count,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof site !== 'undefined' && site && site.length) ? site.map(o => [].concat(o.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -40,6 +48,34 @@ "expandInnerObjects": true }, "matches": "none", + "ui": [ + { + "type": "objects", + "name": "site", + "label": "Site(s) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Site" + ] + } + } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } + } + ], "metadata": [ { "name": "id", @@ -145,6 +181,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/tags.json b/plugins/NetBox/v1/dataStreams/tags.json new file mode 100644 index 00000000..491c69c5 --- /dev/null +++ b/plugins/NetBox/v1/dataStreams/tags.json @@ -0,0 +1,63 @@ +{ + "name": "tags", + "displayName": "Tags", + "description": "Tags as label and slug pairs", + "tags": [ + "Inventory" + ], + "visibility": { + "type": "hidden" + }, + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "api/extras/tags/", + "getArgs": [ + { + "key": "fields", + "value": "id,name,slug" + }, + { + "key": "ordering", + "value": "name" + } + ], + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "limit", + "value": "250" + }, + "offset": { + "mode": "row", + "base": 0, + "rowCountIn": { + "realm": "payloadArraySize", + "path": "results" + } + }, + "out": { + "realm": "queryArg", + "path": "offset" + } + }, + "postRequestScript": "tags.js" + }, + "matches": "none", + "metadata": [ + { + "name": "label", + "displayName": "Label", + "shape": "string", + "role": "label" + }, + { + "name": "value", + "displayName": "Value", + "shape": "string", + "role": "value" + } + ], + "timeframes": false +} diff --git a/plugins/NetBox/v1/dataStreams/virtualMachines.json b/plugins/NetBox/v1/dataStreams/virtualMachines.json index e95e7540..f6dfbb6f 100644 --- a/plugins/NetBox/v1/dataStreams/virtualMachines.json +++ b/plugins/NetBox/v1/dataStreams/virtualMachines.json @@ -13,11 +13,19 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,status,site,cluster,device,role,tenant,platform,primary_ip,vcpus,memory,disk,description,created,last_updated,custom_fields" + "value": "id,display,display_url,status,site,cluster,device,role,tenant,platform,primary_ip,vcpus,memory,disk,description,created,last_updated,tags,custom_fields" + }, + { + "key": "id", + "value": "{{ (typeof virtualMachine !== 'undefined' && virtualMachine && virtualMachine.length) ? virtualMachine.map(o => [].concat(o.rawId)[0]) : null }}" }, { "key": "site_id", "value": "{{ (typeof site !== 'undefined' && site && site.length) ? site.map(s => [].concat(s.rawId)[0]) : null }}" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -45,6 +53,19 @@ }, "matches": "none", "ui": [ + { + "type": "objects", + "name": "virtualMachine", + "label": "Virtual machine(s) (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Virtual Machine" + ] + } + } + }, { "type": "objects", "name": "site", @@ -57,6 +78,19 @@ ] } } + }, + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } } ], "metadata": [ @@ -158,6 +192,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/dataStreams/vlanGroups.json b/plugins/NetBox/v1/dataStreams/vlanGroups.json index 00bb96f4..1d77334e 100644 --- a/plugins/NetBox/v1/dataStreams/vlanGroups.json +++ b/plugins/NetBox/v1/dataStreams/vlanGroups.json @@ -13,7 +13,11 @@ "getArgs": [ { "key": "fields", - "value": "id,display,display_url,name,slug,scope_type,scope,tenant,vid_ranges,total_vlan_ids,vlan_count,utilization,description,last_updated,custom_fields" + "value": "id,display,display_url,name,slug,scope_type,scope,tenant,vid_ranges,total_vlan_ids,vlan_count,utilization,description,last_updated,tags,custom_fields" + }, + { + "key": "tag", + "value": "{{ (typeof tag !== 'undefined' && tag && tag.length) ? [].concat(tag).flatMap(t => (t && typeof t === 'object') ? [t.value] : String(t).split(',')).map(t => String(t).trim()).filter(Boolean) : null }}" } ], "paging": { @@ -50,6 +54,21 @@ ] } }, + "ui": [ + { + "type": "autocomplete", + "name": "tag", + "label": "Tag(s) (optional)", + "help": "Returns only objects that have all the selected tags", + "isMulti": true, + "allowCustomValues": true, + "data": { + "source": "dataStream", + "dataStreamName": "tags", + "dataSourceConfig": {} + } + } + ], "metadata": [ { "name": "id", @@ -129,6 +148,21 @@ "displayName": "Last Updated", "shape": "date" }, + { + "pattern": "^tags[.].*", + "visible": false + }, + { + "name": "tags.0.display", + "displayName": "Tags", + "shape": [ + "array", + { + "itemShape": "string" + } + ], + "valueExpression": "{{ (() => { const out = []; for (let i = 0; i < 100; i++) { const n = $['tags.' + i + '.name']; if (typeof n !== 'string' || !n) break; out.push(n); } return out.length ? JSON.stringify(out) : null; })() }}" + }, { "name": "display_url", "displayName": "Link", diff --git a/plugins/NetBox/v1/docs/README.md b/plugins/NetBox/v1/docs/README.md index 4548479c..58f9f9db 100644 --- a/plugins/NetBox/v1/docs/README.md +++ b/plugins/NetBox/v1/docs/README.md @@ -45,6 +45,7 @@ The plugin works with **NetBox Community**, **NetBox Enterprise**, and **NetBox - **Lifecycle**: devices and virtual machines that aren't active (planned, staged, offline, decommissioning), and circuit termination dates. - **Change activity**: the NetBox change log by user, action and object type over time. - **Custom fields**: every custom field on sites, racks, devices, virtual machines, prefixes, circuits, IP addresses and power feeds appears as an extra column. +- **Tags**: NetBox tags appear as a **Tags** column, can filter list streams, and are stored on imported objects so Collections and scopes can match them. **Dashboards.** The out-of-the-box dashboards are **Overview**, **IPAM Capacity**, **Rack Capacity**, **Data Quality**, **Lifecycle and Circuits**, **Change Activity**, **Data Centers** (including a map of sites), **Power**, and **Device Inventory**. There is also a perspective dashboard for each **Site**, **Rack**, **Device**, **Virtual Machine**, **Prefix** and **Circuit**. @@ -76,6 +77,10 @@ The plugin works with **NetBox Community**, **NetBox Enterprise**, and **NetBox - Build and test queries in NetBox's GraphiQL explorer at `https:///graphql/`. - Add `pagination: { limit: 1000, offset: 0 }` to lists that may be longer than 1,000 items. +**Tags.** Sites, Racks, Devices, Virtual Machines, Prefixes, IP Addresses, VLAN Groups, Circuits and Power Feeds have a **Tags** column and an optional **Tag(s)** filter. When several tags are selected, only objects that have all of them are returned. + +**Selected objects and Collections.** Sites, Racks, Devices, Virtual Machines, Prefixes and Circuits also have an optional object filter (**Site(s)**, **Rack(s)**, **Device(s)**, **Virtual machine(s)**, **Prefix(es)**, **Circuit(s)**). It returns only the selected objects, read live from NetBox, including their custom fields and tags. To show a whole Collection, add a dashboard variable based on the Collection, allow multiple selection, default it to all objects, and bind the filter to that variable. + ## What gets indexed | Object type | API source | Represents | @@ -89,6 +94,8 @@ The plugin works with **NetBox Community**, **NetBox Enterprise**, and **NetBox Each object is identified by its NetBox ID and keeps key properties such as status, site, role and tenant. Each also keeps a link back to the object in NetBox. +Each object also keeps its NetBox tags in the **netboxTags** property, with one value per tag. To build a Collection from a tag, filter the objects on **NetboxTags** and pick the tag. Then bind that Collection to the matching list stream's object filter (see **Selected objects and Collections** above) to see the live custom fields of every object in it. + Imports run every 12 hours by default. Dashboard tiles query NetBox live, but SquaredUp caches results briefly, so use the dashboard's refresh button to see a change straight away. ## Known limitations @@ -110,6 +117,11 @@ Imports run every 12 hours by default. Dashboard tiles query NetBox live, but Sq - **Site map.** - Sites appear on the Data Centers map only if their latitude and longitude are set in NetBox. NetBox doesn't convert addresses into coordinates. - The map uses SmartViz Geo Map. Until it's available in your SquaredUp region, the tile shows a table of sites instead. +- **Tags on imported objects.** Tag changes appear on objects after the next import. The **Tags** column is always live. +- **Custom fields.** + - They aren't indexed, so they can't be used to build Collections or scopes. Use tags to group objects, and the object filters to show custom fields for a Collection. + - Select, multi-select and object custom fields appear as several columns (for example the value and the label, or the object's ID, name and link). Hide the ones you don't need in the tile. +- **Very large object selections.** The selected objects are sent to NetBox in one request, which NetBox (or a proxy in front of it) may reject as too long when many hundreds of objects are selected at once. Split very large Collections across tiles if that happens. - **Change log.** Available for up to 30 days at a time. On busy instances, filter by object, action or object type. - **Reconnecting after plugin updates.** If a plugin update changes how SquaredUp connects to NetBox, open the data source and save it again. - **NetBox version.** diff --git a/plugins/NetBox/v1/indexDefinitions/default.json b/plugins/NetBox/v1/indexDefinitions/default.json index 2f5fd2b2..17f3464a 100644 --- a/plugins/NetBox/v1/indexDefinitions/default.json +++ b/plugins/NetBox/v1/indexDefinitions/default.json @@ -31,6 +31,9 @@ { "timeZone": "time_zone" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } @@ -71,6 +74,9 @@ { "uHeight": "u_height" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } @@ -132,6 +138,9 @@ { "cluster": "cluster.name" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } @@ -175,6 +184,9 @@ { "primaryIp": "primary_ip.display" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } @@ -218,6 +230,9 @@ { "markUtilized": "mark_utilized" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } @@ -255,6 +270,9 @@ { "terminationDate": "termination_date" }, + { + "netboxTags": "tags.0.display" + }, { "netboxUrl": "display_url" } diff --git a/plugins/NetBox/v1/metadata.json b/plugins/NetBox/v1/metadata.json index c1c029bf..e8ca3800 100644 --- a/plugins/NetBox/v1/metadata.json +++ b/plugins/NetBox/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "netbox", "displayName": "NetBox", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "@shawn149", "type": "community"