New Topology view for Netbox

10,274 views
Skip to first unread message

Vas Sadvariy

unread,
Feb 19, 2018, 12:22:23 AM2/19/18
to NetBox

I've been working on a JS based topology visualisation for Netbox and proposed it to Jeremy to include in the distribution but my idea was rejected: https://github.com/digitalocean/netbox/issues/1827


Still, I think that it is pretty cool feature and I am definitely going to use it in my company so I just wanted to share it. Maybe somebody would find it interesting too and we would be able to find a way to integrate it into Netbox in a nice(r) way. Maybe one it would even make it to the upstream =)

Thats how it looks:

You can try it on my demo server here: http://114.142.160.109:8000/dcim/sites/site-1/

There are multiple sites created so feel free to change anything you can. There are probably still bugs as I just started to work on adding Circuits to the topology diagram (it only had devices earlier).

Its the site I am developing on so demo might go down any moment. It is located in Australia, so don't be surprised if it is slow =)

The core stuff: draw, move, add/delete connections should be pretty stable now.


My idea of integration is to create a small archive of new files and linux patch file for existing files. A bash script would copy new files to your existing netbox installation and patch a couple of existing files. There would also be a uninstall script to revert all changes of course. I've already tried this approach and it is working fine with 2.2.8, 2.2.9 and 2.3-develop versions. I'll publish this soon if there would be any interest in it.


Let me know what you all think about it.

Brian Candler

unread,
Feb 19, 2018, 3:52:58 AM2/19/18
to NetBox
It looks really cool... if you could make it a standalone web app that talks to the REST API, *or* something which can be installed as a plugin to Netbox that doesn't touch any of Netbox core, I'd be very interested in using it.

(If it talks to the REST API, could it just be standalone static Javascript that runs entirely in the browser?)

Question: is all the placement of objects automatic, e.g. using neato/fdp algorithm, or does it allow you to place objects explicitly? If the latter, where does it store the placement choices?

Simon Lindermann

unread,
Feb 19, 2018, 4:17:23 AM2/19/18
to NetBox
Like mentioned in the original Issue already I'd happy to make use of this very handy add-on as soon as it becomes available as some sort of plugin or anything. 
Brians suggestions doesn't sound too bad actually. What about creating a completely separate Git repository for this? People would be able to obtain updates and it wouldn't conflict with the netbox core.

Cheers

Vas Sadvariy

unread,
Feb 19, 2018, 4:33:07 AM2/19/18
to NetBox
Yeah, I guess it can be implemented as a completely standalone app but the question would be is where to store coordinates? They are stored in a custom field in device model ATM.
Auto placement is only OK for really simple topologies without redundant links etc, and manually placing each device each time to make some sense on a complicated topology is not really useful.
In order to be able to save coordinates to where they are saved now (custom field in device model) we'd have to have write access to netbox DB via API. Two ways to get there are to use CSRF token for currently authenticated used (just authenticate to netbox and it would work), or ask user for his API token (not his password), then keep session information if you do not want user to paste his token every time etc. I do not really like the second option.

Keeping a complete fork is not an option either, there is just to much work syncing it to upstream.
There was a suggestion to create it as a chrome extension but it would not be possible to obtain CSRF token, the only way to get it is on the server side - using python.

You got some good ideas of how to implement it - please share, I'd happy to discuss them.

Brian Candler

unread,
Feb 19, 2018, 5:46:57 PM2/19/18
to NetBox
On Monday, 19 February 2018 09:33:07 UTC, Vas Sadvariy wrote:
Yeah, I guess it can be implemented as a completely standalone app but the question would be is where to store coordinates? They are stored in a custom field in device model ATM.

I'd suggest a completely separate database.  The table of coordinates can still use netbox's device_id as the primary key; when a new device is created then its coordinates will be missing, but that's just the same as them being null on a newly-created device.

It might still be possible to use Netbox's custom fields, but I have a suspicion that the REST API doesn't support those well at the moment.  (But that might be a worthwhile enhancement which maybe Jeremy would accept?)

Niels Dutry

unread,
Feb 20, 2018, 6:06:41 AM2/20/18
to NetBox
I would like to say this looks awesome, keep up the work man!

Please let me know when the feature is available as standalone module installable via pip.
Would definetly make use of this tool (if it's available that way), makes the topology views and creation of interface connections alot easier!

Regards,
N.


Vas Sadvariy

unread,
Feb 20, 2018, 6:23:48 AM2/20/18
to NetBox
pip? thats something new =)
This feature has exactly 0 (zero) lines of python code in it. I am afraid I'll have to add some before they would let me to publish it as a python package...
It works on the client side completely, it is purely JS based.

Dave Noonan

unread,
Feb 20, 2018, 7:58:33 AM2/20/18
to Vas Sadvariy, NetBox
pip is the python package manager.  "pip install pynetbox", etc.


--
You received this message because you are subscribed to the Google Groups "NetBox" group.
To unsubscribe from this group and stop receiving emails from it, send an email to netbox-discuss+unsubscribe@googlegroups.com.
To post to this group, send email to netbox-discuss@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/netbox-discuss/a3f2f34f-a524-45da-a92e-43073402649c%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Niels Dutry

unread,
Feb 20, 2018, 8:10:36 AM2/20/18
to NetBox
@Dave, I think he knows that already :). 

OP: 
Sorry for the inclarity didn't read it thoroughly that you were describing it as a full JS code.
I just wanted to make clear that it would be nice to have it available as a module and not as a fork.


On Tuesday, February 20, 2018 at 1:58:33 PM UTC+1, Dave Noonan wrote:
pip is the python package manager.  "pip install pynetbox", etc.

On Tue, Feb 20, 2018 at 6:23 AM, Vas Sadvariy <sadv...@gmail.com> wrote:
pip? thats something new =)
This feature has exactly 0 (zero) lines of python code in it. I am afraid I'll have to add some before they would let me to publish it as a python package...
It works on the client side completely, it is purely JS based.

On Tuesday, 20 February 2018 22:06:41 UTC+11, Niels Dutry wrote:
I would like to say this looks awesome, keep up the work man!

Please let me know when the feature is available as standalone module installable via pip.
Would definetly make use of this tool (if it's available that way), makes the topology views and creation of interface connections alot easier!

Regards,
N.


--
You received this message because you are subscribed to the Google Groups "NetBox" group.
To unsubscribe from this group and stop receiving emails from it, send an email to netbox-discus...@googlegroups.com.
To post to this group, send email to netbox-...@googlegroups.com.

Vas Sadvariy

unread,
Apr 6, 2018, 4:23:03 AM4/6/18
to NetBox
Here is the repo: https://github.com/bashioo/netbox_topology
installation process is described there.
let me know if there are any issues.

Simon Lindermann

unread,
Apr 20, 2018, 11:16:51 AM4/20/18
to NetBox
Thank you, installed!

I'm missing a "Save" button to make the topology static as I can only click "Edit" in the top left corner but nothing else.
Also, it doesn't save the topology when I deleted assets/devices which re-appear after every website refresh. Does this happen by design?

Rgds,
Simon

Vas Sadvariy

unread,
Apr 20, 2018, 6:24:57 PM4/20/18
to NetBox
Hi Simon,

What is your Netbox version?
There is no "Save" button by design. Position of individual devices is saved after you finish dragging the device.
"Edit" button should be invisible, it is part of the original functionality of the visualisation module that I do not use.
The same is true for deleting of nodes - the module does not allow adding or deleting of Nodes, only edges.

If you can see "Edit" button it means that patching of original Netbox css files might have failed. Please show me your current (post module installation) css file netbox/static/css/base.css
You sure you also created 'coordinates' custom field as per manual?

Simon Lindermann

unread,
May 4, 2018, 5:27:55 AM5/4/18
to NetBox
Hi Vas,

I'm running 2.3.3 and this is how my custom field is configured:


The position of devices is reset every time I refresh the site or navigate back to it as well as deleted devices re-appear. Below you can find my base.css values.

Thanks,
Simon

/* Layout */
* {
    margin: 0;
}
html {
    overflow-y: scroll;
}
html, body {
    height: 100%;
}
body {
    padding-top: 70px;
}
.container {
    width: auto;
    max-width: 1600px;
}
.wrapper {
    min-height: 100%;
    height: auto !important;
    margin: 0 auto -61px; /* the bottom margin is the negative value of the footer's height */
    padding-bottom: 30px;
}
.navbar-brand {
    padding: 12px 15px 8px;
}
.footer, .push {
    height: 60px; /* .push must be the same height as .footer */
}
.footer {
    background-color: #f5f5f5;
    border-top: 1px solid #d0d0d0;
}
footer p {
    margin: 20px 0;
}

/* Hide the username in the navigation menu on displays less than 1400px wide */
@media (max-width: 1399px) {
    #navbar_user {
        display: none;
    }
}

/* Hide the search bar in the navigation menu on displays less than 1200px wide */
@media (max-width: 1199px) {
    #navbar_search {
        display: none;
    }
}

/* Collapse the nav menu on displays less than 960px wide */
@media (max-width: 959px) {
    .navbar-header {
        float: none;
    }
    .navbar-left,.navbar-right {
        float: none !important;
    }
    .navbar-toggle {
        display: block;
    }
    .navbar-collapse {
        border-top: 1px solid transparent;
        box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
    }
    .navbar-fixed-top {
        top: 0;
        border-width: 0 0 1px;
    }
    .navbar-collapse.collapse {
        display: none!important;
        max-height: none;
    }
    .navbar-nav {
        float: none !important;
        margin-top: 7.5px;
    }
    .navbar-nav>li {
        float: none;
    }
    .navbar-nav>li>a {
        padding-top: 10px;
        padding-bottom: 10px;
    }
    .collapse.in {
        display:block !important;
    }
    #navbar_user {
        display: inline;
    }
}

/* Navigation menu */
li.subnav > a {
    padding-left: 30px;
}
ul.dropdown-menu {
    width: 250px;
}
ul.dropdown-menu div.buttons {
    padding-right: 10px;
    padding-top: 2px;
}
ul.dropdown-menu div.buttons a {
    width: 26px;
}
ul.dropdown-menu > li > a {
    clear: left;
}

/* Forms */
label {
    font-weight: normal;
}
label.required {
    font-weight: bold;
}
input[name="pk"] {
    margin-top: 0;
}

/* Tables */
    padding-bottom: 6px;
    padding-top: 10px;
    width: 30px;
}
tfoot td {
    font-weight: bold;
}
table.attr-table td:nth-child(1) {
    width: 25%;
}
.table-headings th {
    background-color: #f5f5f5;
}

/* Paginator */
div.paginator {
    margin-bottom: 20px;
}
nav ul.pagination {
    margin-top: 0;
    margin-bottom: 8px !important;
}

/* Racks */
div.rack_header {
    margin-left: 36px;
    text-align: center;
    width: 230px;
}
ul.rack_legend {
    float: left;
    list-style-type: none;
    margin-right: 6px;
    padding: 0;
    width: 30px;
}
ul.rack_legend li {
    color: #c0c0c0;
    display: block;
    font-size: 10px;
    height: 20px;
    overflow: hidden;
    padding: 5px 0;
    text-align: right;
}
div.rack_frame {
    float: left;
    position: relative;
}
ul.rack {
    border: 2px solid #404040;
    float: left;
    list-style-type: none;
    padding: 0;
    position: absolute;
    width: 230px;
}
ul.rack li {
    border-top: 1px solid #e0e0e0;
    display: block;
    font-size: 13px;
    height: 20px;
    overflow: hidden;
    text-align: center;
}
ul.rack li.h2u { height: 40px; }
ul.rack li.h2u a, ul.rack li.h2u span { padding: 10px 0; }
ul.rack li.h3u { height: 60px; }
ul.rack li.h3u a, ul.rack li.h3u span { padding: 20px 0; }
ul.rack li.h4u { height: 80px; }
ul.rack li.h4u a, ul.rack li.h4u span { padding: 30px 0; }
ul.rack li.h5u { height: 100px; }
ul.rack li.h5u a, ul.rack li.h5u span { padding: 40px 0; }
ul.rack li.h6u { height: 120px; }
ul.rack li.h6u a, ul.rack li.h6u span { padding: 50px 0; }
ul.rack li.h7u { height: 140px; }
ul.rack li.h7u a, ul.rack li.h7u span { padding: 60px 0; }
ul.rack li.h8u { height: 160px; }
ul.rack li.h8u a, ul.rack li.h8u span { padding: 70px 0; }
ul.rack li.h9u { height: 180px; }
ul.rack li.h9u a, ul.rack li.h9u span { padding: 80px 0; }
ul.rack li.h10u { height: 200px; }
ul.rack li.h10u a, ul.rack li.h10u span { padding: 90px 0; }
ul.rack li.h11u { height: 220px; }
ul.rack li.h11u a, ul.rack li.h11u span { padding: 100px 0; }
ul.rack li.h12u { height: 240px; }
ul.rack li.h12u a, ul.rack li.h12u span { padding: 110px 0; }
ul.rack li.h13u { height: 260px; }
ul.rack li.h13u a, ul.rack li.h13u span { padding: 120px 0; }
ul.rack li.h14u { height: 280px; }
ul.rack li.h14u a, ul.rack li.h14u span { padding: 130px 0; }
ul.rack li.h15u { height: 300px; }
ul.rack li.h15u a, ul.rack li.h15u span { padding: 140px 0; }
ul.rack li.h16u { height: 320px; }
ul.rack li.h16u a, ul.rack li.h16u span { padding: 150px 0; }
ul.rack li.h17u { height: 340px; }
ul.rack li.h17u a, ul.rack li.h17u span { padding: 160px 0; }
ul.rack li.h18u { height: 360px; }
ul.rack li.h18u a, ul.rack li.h18u span { padding: 170px 0; }
ul.rack li.h19u { height: 380px; }
ul.rack li.h19u a, ul.rack li.h19u span { padding: 180px 0; }
ul.rack li.h20u { height: 400px; }
ul.rack li.h20u a, ul.rack li.h20u span { padding: 190px 0; }
ul.rack li.h21u { height: 420px; }
ul.rack li.h21u a, ul.rack li.h21u span { padding: 200px 0; }
ul.rack li.h22u { height: 440px; }
ul.rack li.h22u a, ul.rack li.h22u span { padding: 210px 0; }
ul.rack li.h23u { height: 460px; }
ul.rack li.h23u a, ul.rack li.h23u span { padding: 220px 0; }
ul.rack li.h24u { height: 480px; }
ul.rack li.h24u a, ul.rack li.h24u span { padding: 230px 0; }
ul.rack li.h25u { height: 500px; }
ul.rack li.h25u a, ul.rack li.h25u span { padding: 240px 0; }
ul.rack li.h26u { height: 520px; }
ul.rack li.h26u a, ul.rack li.h26u span { padding: 250px 0; }
ul.rack li.h27u { height: 540px; }
ul.rack li.h27u a, ul.rack li.h27u span { padding: 260px 0; }
ul.rack li.h28u { height: 560px; }
ul.rack li.h28u a, ul.rack li.h28u span { padding: 270px 0; }
ul.rack li.h29u { height: 580px; }
ul.rack li.h29u a, ul.rack li.h29u span { padding: 280px 0; }
ul.rack li.h30u { height: 600px; }
ul.rack li.h30u a, ul.rack li.h30u span { padding: 290px 0; }
ul.rack li.h31u { height: 620px; }
ul.rack li.h31u a, ul.rack li.h31u span { padding: 300px 0; }
ul.rack li.h32u { height: 640px; }
ul.rack li.h32u a, ul.rack li.h32u span { padding: 310px 0; }
ul.rack li.h33u { height: 660px; }
ul.rack li.h33u a, ul.rack li.h33u span { padding: 320px 0; }
ul.rack li.h34u { height: 680px; }
ul.rack li.h34u a, ul.rack li.h34u span { padding: 330px 0; }
ul.rack li.h35u { height: 700px; }
ul.rack li.h35u a, ul.rack li.h35u span { padding: 340px 0; }
ul.rack li.h36u { height: 720px; }
ul.rack li.h36u a, ul.rack li.h36u span { padding: 350px 0; }
ul.rack li.h37u { height: 740px; }
ul.rack li.h37u a, ul.rack li.h37u span { padding: 360px 0; }
ul.rack li.h38u { height: 760px; }
ul.rack li.h38u a, ul.rack li.h38u span { padding: 370px 0; }
ul.rack li.h39u { height: 780px; }
ul.rack li.h39u a, ul.rack li.h39u span { padding: 380px 0; }
ul.rack li.h40u { height: 800px; }
ul.rack li.h40u a, ul.rack li.h40u span { padding: 390px 0; }
ul.rack li.h41u { height: 820px; }
ul.rack li.h41u a, ul.rack li.h41u span { padding: 400px 0; }
ul.rack li.h42u { height: 840px; }
ul.rack li.h42u a, ul.rack li.h42u span { padding: 410px 0; }
ul.rack li.h43u { height: 860px; }
ul.rack li.h43u a, ul.rack li.h43u span { padding: 420px 0; }
ul.rack li.h44u { height: 880px; }
ul.rack li.h44u a, ul.rack li.h44u span { padding: 430px 0; }
ul.rack li.h45u { height: 900px; }
ul.rack li.h45u a, ul.rack li.h45u span { padding: 440px 0; }
ul.rack li.h46u { height: 920px; }
ul.rack li.h46u a, ul.rack li.h46u span { padding: 450px 0; }
ul.rack li.h47u { height: 940px; }
ul.rack li.h47u a, ul.rack li.h47u span { padding: 460px 0; }
ul.rack li.h48u { height: 960px; }
ul.rack li.h48u a, ul.rack li.h48u span { padding: 470px 0; }
ul.rack li.h49u { height: 980px; }
ul.rack li.h49u a, ul.rack li.h49u span { padding: 480px 0; }
ul.rack li.h50u { height: 1000px; }
ul.rack li.h50u a, ul.rack li.h50u span { padding: 490px 0; }
ul.rack_far_face {
    background-color: #f7f7f7;
    z-index: 100;
}
ul.rack_far_face li.occupied {
    background: repeating-linear-gradient(
        45deg,
        #f7f7f7,
        #f7f7f7 7px,
        #f0f0f0 7px,
        #f0f0f0 14px
    );
}
ul.rack_far_face li.blocked {
    background: repeating-linear-gradient(
        45deg,
        #f7f7f7,
        #f7f7f7 7px,
        #ffc7c7 7px,
        #ffc7c7 14px
    );
}
ul.rack_near_face li.reserved {
    background: repeating-linear-gradient(
        45deg,
        #f7f7f7,
        #f7f7f7 7px,
        #c7c7ff 7px,
        #c7c7ff 14px
    );
}
ul.rack_near_face {
    z-index: 200;
}
ul.rack_near_face li.occupied {
    border-top: 1px solid #474747;
    color: #474747;
}
ul.rack_near_face li.occupied:hover {
    background-image: url('../img/tint_20.png');
}
ul.rack_near_face li:first-child {
    border-top: 0;
}
ul.rack_near_face li.available a {
    color: #0000ff;
    display: none;
    text-decoration: none;
}
ul.rack_near_face li.available:hover {
    background-color: #ffffff;
}
ul.rack_near_face li.available:hover a {
    display: block;
}
ul.rack li.occupied a {
    color: #ffffff;
    display: block;
    font-weight: bold;
}
ul.rack li.occupied a:hover {
    text-decoration: none;
}
ul.rack li.occupied span {
    cursor: default;
    display: block;
}
li.occupied + li.available {
    border-top: 1px solid #474747;
}

/* Devices */
table.component-list td.subtable {
    padding: 0;
    padding-left: 16px;
}
table.component-list td.subtable td {
    border: none;
    padding-bottom: 6px;
    padding-top: 6px;
}

/* Reports */
table.reports td.method {
    font-family: monospace;
    padding-left: 30px;
}
table.reports td.stats label {
    display: inline-block;
    line-height: 14px;
    margin-bottom: 0;
    min-width: 40px;
}

/* AJAX loader */
.loading {
    position: fixed;
    display: none;
    z-index: 999;
    height: 2em;
    width: 2em;
    overflow: show;
    margin: auto;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
}
.loading:before {
    content: '';
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,0.3);
}

/* Misc */
.text-nowrap {
    white-space: nowrap;
}
.banner-bottom {
    margin-bottom: 50px;
}
.panel table {
    margin-bottom: 0;
}
.panel .table th {
    border-bottom-width: 1px;
}
.panel table tr.even:first-child td {
    border-top: 0;
}
.panel .list-group {
    max-height: 400px;
    overflow: auto;
}
ul.nav-tabs, ul.nav-pills {
    margin-bottom: 20px;
}
/* Fix progress bar margin inside table cells */
td .progress {
    margin-bottom: 0;
}
textarea {
    font-family: Consolas, Lucida Console, monospace;
}
/* Vis JS hide built-in manipulation panel */
.vis-edit, .vis-edit-mode, .vis-close, .vis-back, .vis-separator-line {
    display: none !important;
    background-image: none !important;
}
.vis-manipulation {
    background-color: #fff !important;
    border: 0 !important;
}
/* JQuery hide dialog close button */
.ui-dialog-titlebar-close {
    display: none;
}


Vasily Sadvariy

unread,
May 4, 2018, 6:35:11 AM5/4/18
to Simon Lindermann, NetBox
Hi Simon,

It looks like you've bound the coordinates field to the wrong model. It should be bound to "Device", not "Device Type". The idea is to have a set of coordinates per device not per type. Try deleting the existing field and creating a new one against the Device model instead. This should solve your problem with position not being saved.

As for deleted devices it is even easier. The JS library I used for drawing (visjs) supports all kinds of modifications of the graph but I had to limit its abilities as I intentionally newer planned to allow addition or deletion of devices via its GUI. I did it by hiding manipulation elements which is probably not the right way of doing it. I should have cut this functionality completely from the library instead. So now you probably can see some interface elements that should have been hidden and can delete nodes from the graph. However, this has no effect to the actual devices in the database as the script does not have any code to actually delete/create devices from DB, so what you modify is only a visjs representation. Therefore the next time you refresh the page all the devices will reappear.

If you want some devices hidden I've added this functionality recently. You can uninstall your old version, download and install the new one and use config file to hide specific devices by role.
If you want to delete a device just use regular Netbox Devices interface to do it.

Can you please show me the screenshot of your topology panel, only manipulation interface on the top is enough? 



Best regards,
Vasily Sadvariy

--
You received this message because you are subscribed to a topic in the Google Groups "NetBox" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/netbox-discuss/MRp0I6nS5xc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to netbox-discuss+unsubscribe@googlegroups.com.
To post to this group, send email to netbox-discuss@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/netbox-discuss/98a5dd92-4cb3-4d10-a637-95e20b7cf416%40googlegroups.com.

Simon Lindermann

unread,
May 9, 2018, 5:35:43 AM5/9/18
to NetBox
Hi Vasily,

Works with the correct coordinates field, thanks! :)

I uninstalled and reinstalled it again. Where can I find the config file you mentioned? I do not want to delete the devices from the netbox DB, just remove them from the topology view (since power supplies or extension cards are not really helpful in there).

Rgds,
Simon


Best regards,
Vasily Sadvariy

To unsubscribe from this group and all its topics, send an email to netbox-discus...@googlegroups.com.
To post to this group, send email to netbox-...@googlegroups.com.

Simon Lindermann

unread,
May 9, 2018, 5:52:29 AM5/9/18
to NetBox
I think I found the config file in: /opt/netbox/netbox_topology/netbox/static/js/topology_config.json
This may work for me if I can filter on device types or names rather than roles.

Rgds,
Simon

joey c

unread,
Jul 25, 2018, 1:09:40 AM7/25/18
to NetBox
Not sure if this is still under development, but im digging through that demo server and i don't see the visualization anywhere. Is it still active?

Niels Dutry

unread,
Aug 10, 2018, 11:08:30 AM8/10/18
to NetBox
Ohnoes it stopped working in netbox 2.4.3 :D

Op maandag 19 februari 2018 06:22:23 UTC+1 schreef Vas Sadvariy:

Vas Sadvariy

unread,
Aug 10, 2018, 7:00:34 PM8/10/18
to NetBox
oops. But I always expected that to happen one day tbh

What a timing though =) Yesterday was the last day at the company I originally developed all these extensions for so I would not be able to support them anymore.

At least one of my changes made to to the upstream: https://github.com/digitalocean/netbox/pull/2096

Not this one, although I liked it more =)

Cheers,
Vas

Vas Sadvariy

unread,
Aug 10, 2018, 11:50:07 PM8/10/18
to NetBox
Just had a quick look and it was a really easy fix actually.

The repo has been updated to support both pre and post 2.4.3 models. Please pull the changes and reinstall. Let me know if there are any issues. Live demo is live again on the old IP.


Cheers,
Vas

Niels Dutry

unread,
Aug 16, 2018, 10:40:47 AM8/16/18
to NetBox
Thanks man, cheers!
Glad you had a change request that made it to the upstream :-)! 

Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:

Niels Dutry

unread,
Aug 16, 2018, 10:58:51 AM8/16/18
to NetBox
I have altered the HTML a little so bigger sites are easier to view within your brower. I also commented out the topology maps sections, since I don't want to have a duplicate container.
In short I've added an extra row-div with a column width of 12 below all other information in the /netbox/templates/dcim/site.html:
{% extends '_base.html' %}
{% load static from staticfiles %}
{% load tz %}
{% load helpers %}

{% block header %}
    <div class="row">
        <div class="col-sm-8 col-md-9">
            <ol class="breadcrumb">
                <li><a href="{% url 'dcim:site_list' %}">Sites</a></li>
                {% if site.region %}
                    {% for region in site.region.get_ancestors %}
                        <li><a href="{{ region.get_absolute_url }}">{{ region }}</a></li>
                    {% endfor %}
                    <li><a href="{{ site.region.get_absolute_url }}">{{ site.region }}</a></li>
                {% endif %}
                <li>{{ site }}</li>
            </ol>
        </div>
        <div class="col-sm-4 col-md-3">
            <form action="{% url 'dcim:site_list' %}" method="get">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="Search sites" />
                    <span class="input-group-btn">
                        <button type="submit" class="btn btn-primary">
                            <span class="fa fa-search" aria-hidden="true"></span>
                        </button>
                    </span>
                </div>
            </form>
        </div>
    </div>
    <div class="pull-right">
        {% if show_graphs %}
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ site.name }}" data-url="{% url 'dcim-api:site-graphs' pk=site.pk %}" title="Show graphs">
                <i class="fa fa-signal" aria-hidden="true"></i>
                Graphs
            </button>
        {% endif %}
        {% if perms.dcim.change_site %}
            <a href="{% url 'dcim:site_edit' slug=site.slug %}" class="btn btn-warning">
                <span class="fa fa-pencil" aria-hidden="true"></span>
                Edit this site
            </a>
        {% endif %}
        {% if perms.dcim.delete_site %}
            <a href="{% url 'dcim:site_delete' slug=site.slug %}" class="btn btn-danger">
                <span class="fa fa-trash" aria-hidden="true"></span>
                Delete this site
            </a>
        {% endif %}
    </div>
    <h1>{% block title %}{{ site }}{% endblock %}</h1>
    {% include 'inc/created_updated.html' with obj=site %}
    <ul class="nav nav-tabs">
        <li role="presentation"{% if not active_tab %} class="active"{% endif %}>
            <a href="{{ site.get_absolute_url }}">Site</a>
        </li>
        <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
            <a href="{% url 'dcim:site_changelog' slug=site.slug %}">Changelog</a>
        </li>
    </ul>
{% endblock %}

{% block stylesheet %}
    <link rel="stylesheet" href="{% static 'vis-4.21.0/vis-network.min.css' %}">
{% endblock %}

{% block content %}
<div class="row">
<div class="col-md-7">
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Site</strong>
            </div>
            <table class="table table-hover panel-body attr-table">
                <tr>
                    <td>Status</td>
                    <td>
                        <span class="label label-{{ site.get_status_class }}">{{ site.get_status_display }}</span>
                    </td>
                </tr>
                <tr>
                    <td>Region</td>
                    <td>
                        {% if site.region %}
                            {% for region in site.region.get_ancestors %}
                                <a href="{{ region.get_absolute_url }}">{{ region }}</a>
                                <i class="fa fa-angle-right"></i>
                            {% endfor %}
                            <a href="{{ site.region.get_absolute_url }}">{{ site.region }}</a>
                        {% else %}
                            <span class="text-muted">None</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Tenant</td>
                    <td>
                        {% if site.tenant %}
                            {% if site.tenant.group %}
                                <a href="{{ site.tenant.group.get_absolute_url }}">{{ site.tenant.group }}</a>
                                <i class="fa fa-angle-right"></i>
                            {% endif %}
                            <a href="{{ site.tenant.get_absolute_url }}">{{ site.tenant }}</a>
                        {% else %}
                            <span class="text-muted">None</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Facility</td>
                    <td>
                        {% if site.facility %}
                            {{ site.facility }}
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>AS Number</td>
                    <td>
                        {% if site.asn %}
                            {{ site.asn }}
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Time Zone</td>
                    <td>
                        {% if site.time_zone %}
                            {{ site.time_zone }} (UTC {{ site.time_zone|tzoffset }})<br />
                            <small class="text-muted">Site time: {% timezone site.time_zone %}{% now "SHORT_DATETIME_FORMAT" %}{% endtimezone %}</small>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Description</td>
                    <td>
                        {% if site.description %}
                            {{ site.description }}
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
            </table>
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Contact Info</strong>
            </div>
            <table class="table table-hover panel-body attr-table">
                <tr>
                    <td>Physical Address</td>
                    <td>
                        {% if site.physical_address %}
                            <div class="pull-right">
                                <a href="http://maps.google.com/?q={{ site.physical_address|oneline }}" target="_blank" class="btn btn-primary btn-xs">
                                    <i class="glyphicon glyphicon-map-marker"></i> Map it
                                </a>
                            </div>
                            <span>{{ site.physical_address|linebreaksbr }}</span>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Shipping Address</td>
                    <td>
                        {% if site.shipping_address %}
                            <span>{{ site.shipping_address|linebreaksbr }}</span>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>GPS Coordinates</td>
                    <td>
                        {% if site.latitude and site.longitude %}
                            <div class="pull-right">
                                <a href="http://maps.google.com/?q={{ site.latitude }},{{ site.longitude }}" target="_blank" class="btn btn-primary btn-xs">
                                    <i class="glyphicon glyphicon-map-marker"></i> Map it
                                </a>
                            </div>
                            <span>{{ site.latitude }}, {{ site.longitude }}</span>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Contact Name</td>
                    <td>
                        {% if site.contact_name %}
                            <span>{{ site.contact_name }}</span>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Contact Phone</td>
                    <td>
                        {% if site.contact_phone %}
                            <a href="tel:{{ site.contact_phone }}">{{ site.contact_phone }}</a>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
                <tr>
                    <td>Contact E-Mail</td>
                    <td>
                        {% if site.contact_email %}
                            <a href="mailto:{{ site.contact_email }}">{{ site.contact_email }}</a>
                        {% else %}
                            <span class="text-muted">N/A</span>
                        {% endif %}
                    </td>
                </tr>
            </table>
        </div>
        {% include 'inc/custom_fields_panel.html' with obj=site %}
        {% include 'extras/inc/tags_panel.html' with tags=site.tags.all url='dcim:site_list' %}
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Comments</strong>
            </div>
            <div class="panel-body">
                {% if site.comments %}
                    {{ site.comments|gfm }}
                {% else %}
                    <span class="text-muted">None</span>
                {% endif %}
            </div>
        </div>
    </div>
    <div class="col-md-5">
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Stats</strong>
            </div>
            <div class="row panel-body">
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'dcim:rack_list' %}?site={{ site.slug }}" class="btn {% if stats.rack_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.rack_count }}</a></h2>
                    <p>Racks</p>
                </div>
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'dcim:device_list' %}?site={{ site.slug }}" class="btn {% if stats.device_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.device_count }}</a></h2>
                    <p>Devices</p>
                </div>
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'ipam:prefix_list' %}?site={{ site.slug }}" class="btn {% if stats.prefix_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.prefix_count }}</a></h2>
                    <p>Prefixes</p>
                </div>
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'ipam:vlan_list' %}?site={{ site.slug }}" class="btn {% if stats.vlan_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.vlan_count }}</a></h2>
                    <p>VLANs</p>
                </div>
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'circuits:circuit_list' %}?site={{ site.slug }}" class="btn {% if stats.circuit_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.circuit_count }}</a></h2>
                    <p>Circuits</p>
                </div>
                <div class="col-md-4 text-center">
                    <h2><a href="{% url 'virtualization:virtualmachine_list' %}?site={{ site.slug }}" class="btn {% if stats.vm_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.vm_count }}</a></h2>
                    <p>Virtual Machines</p>
                </div>
            </div>
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Rack Groups</strong>
            </div>
            {% if rack_groups %}
                <table class="table table-hover panel-body">
                    {% for rg in rack_groups %}
                        <tr>
                            <td><i class="fa fa-fw fa-folder-o"></i> <a href="{{ rg.get_absolute_url }}">{{ rg }}</a></td>
                            <td>{{ rg.rack_count }}</td>
                            <td class="text-right">
                                <a href="{% url 'dcim:rack_elevation_list' %}?group_id={{ rg.pk }}" class="btn btn-xs btn-primary" title="View elevations">
                                    <i class="fa fa-eye"></i>
                                </a>
                            </td>
                        </tr>
                    {% endfor %}
                </table>
            {% else %}
                <div class="panel-body text-muted">
                    None
                </div>
            {% endif %}
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Images</strong>
            </div>
            {% include 'inc/image_attachments.html' with images=site.images.all %}
            {% if perms.extras.add_imageattachment %}
                <div class="panel-footer text-right">
                    <a href="{% url 'dcim:site_add_image' object_id=site.pk %}" class="btn btn-primary btn-xs">
                        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
                        Attach an image
                    </a>
                </div>
            {% endif %}
        </div>
        <!--<div class="panel panel-default">
            <div class="panel-heading">
                <strong>Topology Maps</strong>
            </div>
            {% if topology_maps %}
                <table class="table table-hover panel-body">
                    {% for tm in topology_maps %}
                        <tr>
                            <td><i class="fa fa-fw fa-map-o"></i> <a href="{% url 'extras-api:topologymap-render' pk=tm.pk %}" target="_blank">{{ tm }}</a></td>
                            <td>{{ tm.description }}</td>
                        </tr>
                    {% endfor %}
                </table>
            {% else %}
                <div class="panel-body text-muted">
                    None
                </div>
            {% endif %}
        </div>!-->
</div>
</div>

<div class="row">
<div class="col-md-5">
        <div class="panel panel-default">
            <div class="panel-heading">
                <strong>Topology</strong>
            </div>
            <div class="panel-body">
                <div id="visjsgraph"></div>
            </div>
            {% if perms.dcim.delete_interfaceconnection or perms.dcim.add_interfaceconnection or perms.dcim.change_device%}
            <div class="panel-footer text-right">
                {% if perms.dcim.delete_interfaceconnection %}
                <div id="topology_delete_edge" class="btn btn-primary btn-xs disabled">
                    <span class="glyphicon glyphicon-minus" aria-hidden="true"></span>
                    <span id="topology_delete_edge_label">Delete selected</span>
                </div>
                {% endif %}
                {% if perms.dcim.add_interfaceconnection %}
                <div id="topology_add_edge" class="btn btn-primary btn-xs">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
                    <span id="topology_add_edge_label">New connection</span>
                </div>
                {% endif %}
                {% if perms.dcim.change_device %}
                <div id="topology_reset_coordinates" class="btn btn-primary btn-xs">
                    <span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
                    <span>Reset coordinates</span>
                </div>
                {% endif %}
            </div>
            {% endif %}
        </div>
    </div>
        <div id="add_connection_dialog" title="Creating a new connection" style="display: none;">
        <div style="display: inline-block; margin-bottom:5px; width: 100%">
            <label class="col-xs-5 control-label required" id="device_a_label" for="device_a_interfaces"></label>
            <div class="col-xs-7">
                <select class="form-control" id="device_a_interfaces"></select>
            </div>
        </div>
        <div style="display: inline-block; margin-bottom:5px; width: 100%">
            <label class="col-xs-5 control-label required" id="device_b_label" for="device_b_interfaces"></label>
            <div class="col-xs-7">
                <select class="form-control" id="device_b_interfaces"></select>
            </div>
        </div>
        <div style="display: inline-block; margin-bottom:5px; width: 100%">
            <label class="col-xs-5 control-label required" for="connection_status">Status</label>
            <div class="col-xs-7">
                <select class="form-control" id="connection_status">
                    <option value='True'>Connected</option>
                    <option value='False'>Planned</option>
                </select>
            </div>
        </div>
    </div>
    <div id="delete_connection_dialog" title="Deleting existing connection" style="display: none;">
        <span id="delete_connection_label"></span>
    </div>
</div>

        
{% include 'inc/graphs_modal.html' %}
{% endblock %}

{% block javascript %}
<script src="{% static 'js/graphs.js' %}?v{{ settings.VERSION }}"></script>
<script src="{% static 'vis-4.21.0/vis-network.min.js' %}"></script>
<script>
var TOPOLOGY_IMG_DIR = "{% static 'img/topology/' %}";
var TOKEN = "{{ csrf_token }}";
var SITE_SLUG = "{{ site.slug }}";
{% if perms.dcim.change_device %}
var CHANGE_DEVICE_ALLOWED = true;
{% else %}
var CHANGE_DEVICE_ALLOWED = false;
{% endif %}
</script>
<script src="{% static 'js/topology.js' %}"></script>
{% endblock %}


Now it looks like:

Selection_084.jpg






Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:
Just had a quick look and it was a really easy fix actually.
Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:
Just had a quick look and it was a really easy fix actually.
Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:
Just had a quick look and it was a really easy fix actually.
Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:
Just had a quick look and it was a really easy fix actually.
Op zaterdag 11 augustus 2018 05:50:07 UTC+2 schreef Vas Sadvariy:
Just had a quick look and it was a really easy fix actually.

Vas Sadvariy

unread,
Aug 17, 2018, 3:18:31 AM8/17/18
to Niels Dutry, NetBox
Hi Niels,

Looks good. If you could please submit it as a pull request I'd be happy to add it to the repository.

Best regards,
Vas Sadvariy


--
You received this message because you are subscribed to a topic in the Google Groups "NetBox" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/netbox-discuss/MRp0I6nS5xc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to netbox-discus...@googlegroups.com.
To post to this group, send email to netbox-...@googlegroups.com.

Ben Lockwood

unread,
Nov 19, 2018, 12:21:49 PM11/19/18
to NetBox
Hi there,

I just started experimenting with your netbox_topologys and i really love it, but i have one question and a request:

  • How do i select which symbol is used for which device role? it seems to be detecting my routers correctly, but other devices are all using a generic icon. Is there a list of available icons and a way to bind them to device roles?

  • Would it be possible to somehow generate a global topology? similar to how netbox's native topology maps allow for a map to not be tied to a site, but instead be accessible from a link on the homepage, having this option on your far superior system would be awesome
Thank you very much for your work, this is far superior to the built in system for topology maps

On Monday, February 19, 2018 at 12:22:23 AM UTC-5, Vas Sadvariy wrote:

Vas Sadvariy

unread,
Nov 19, 2018, 6:49:41 PM11/19/18
to benlock...@gmail.com, netbox-...@googlegroups.com
Hi Ben,

Thanks for your interest in my topology module.

You can change what icons are displayed for each device type by adding/renaming files in "netbox/static/img/topology" directory. Each file there represents a device type and is bound to it by SLUG field of your device types. So if you want to change the image for device type named "My device" with slug "my_device" just create a file in the above directory with the name of "my_device.png".

As for global topology, you sure can turn it on by modifying the code but:
1. I have never tested it and have no idea if it will wok or not,
2. It might be big or even HUGE based on a number of devices in your database,
3. Intersite links are usually not connected directly but rather via uplink providers (circuits in netbox terminology), and while it is possible to parse and display this data (I started some work on it but never completed it) I have not got chance to include it in the current topology module

If you still want to try just modify the source file /netbox/static/js/topology.js and remove mention of SITE_SLUG variable from API calls, so the first parameter to api_call function on line 58 will be "/api/dcim/devices/?limit=0" instead of "/api/dcim/devices/?limit=0&site="+SITE_SLUG. Do the same with connections on line 87.

Best regards,
Vas Sadvariy


--
You received this message because you are subscribed to a topic in the Google Groups "NetBox" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/netbox-discuss/MRp0I6nS5xc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to netbox-discus...@googlegroups.com.
To post to this group, send email to netbox-...@googlegroups.com.

Ben Lockwood

unread,
Nov 20, 2018, 9:04:37 AM11/20/18
to NetBox
Hi Vas,

Thank you for your reply, that was actually very helpful, regarding the global topology, our organization is not incredibly large so i'm thinking a global topology map would do okay but there would definitely be some problems with scale. For the sake of testing i would like to create a basic html page at /media/global_topology.html that would only contain the global topology map while not affecting the site specific topologies.  to this end i created a copy of /netbox/static/js/topology.js called global_topology.js where i made the change you suggested, however I am having trouble creating a page to achieve this. I've attempted to port the site.html page without much success. Any guidance you could provide would be greatly appreciated.

Thank you,

Ben

Vas Sadvariy

unread,
Nov 20, 2018, 3:21:05 PM11/20/18
to Ben Lockwood, netbox-...@googlegroups.com
Hi Ben,

There are a number of moving parts that create a topology. Just start step by step, add debug messages (console.log()) and try to split the task. Not sure what your experience is with JS and HTML but that is what you'll need mostly to achieve your goal. Check your browser's console as all the JS errors should appear there.

When you mentioned porting site.html, was it porting of the site template or of a rendered webpage? Template site.html expects some variables to be passed to it by Django rendering (like perms, site, etc), once you call the page from media you probably do not have them so you'll need to hardcode or delete them manually.

Sorry, not sure if I would be able to provide much help here with your custom project but feel free to reach out if you have more specific question regarding module logic.

Best regards,
Vas Sadvariy


Ben Lockwood

unread,
Nov 22, 2018, 2:52:30 PM11/22/18
to NetBox
Thanks again for your help, I'm making progress and will share when i've finished, I'm basically cloning the entire plugin and having instances run concurrently so i can still have the site topologies while having a second for global (second custom field called global-coordinates, etc)

For now, i worked on adding more icons to the plugin and ended up using the cisco network device icon pack because it was the largest pack i could find. to this end I was wondering if you know how i might go about making certain devices larger than others, for example, the two cloud icons on the below map i would like to have be 2-3x the size of the rest. (zoomed out for the sake of privacy)

Also, if anyone is interested in the icons i can set up a fork to share them, let me know.

topology.PNG

Ben Lockwood

unread,
Nov 23, 2018, 3:42:00 PM11/23/18
to NetBox
I was able to figure out a way to do it by adding to the topology.js script. its not very elegant and if there is a better way to achieve this please let me know, but if anyone is trying to do the same, i edited the api call where it loads the devices and updated node.size for the devices i wanted to make larger:

api_call("/static/js/topology_config.json", "GET", undefined, function(config) {
   
var hidden_roles = config.hidden_roles;

   
// load devices
    api_call
("/api/dcim/devices/?limit=0&site="+SITE_SLUG, "GET", undefined, function(response) {
       $
.each(response.results, function(index, device) {
           
if (hidden_roles.includes(device.device_role.slug)) {
               console
.log(device.name+' has been hidden because of its role '+device.device_role.slug$
               
return undefined;
           
}
           
var node = {
               id
: device.id,
               name
: device.name,
               label
: '*'+device.name+'*\n'+device.device_type.model,
               image
: TOPOLOGY_IMG_DIR + device.device_role.slug+'.png',
               title
: device.device_role.name+'<br>'
                   
+device.name+'<br>'
                   
+device.device_type.manufacturer.name+' '+device.device_type.model+'<br>'
                   
+'SN: '+device.serial,
           
}
           
if (device.custom_fields.coordinates){
               
var coordinates = device.custom_fields.coordinates.split(";");
                node
.x = parseInt(coordinates[0]);
                node
.y = parseInt(coordinates[1]);
                node
.physics = false;

           
}
         
 if (device.device_role.name  === 'MPLS'){
               node
.size = 80;
           
}
           
if (device.device_role.name === 'Internet'){
               node
.size = 80;
           
}
           
if (device.device_role.name === 'Core Switch'){
               node
.size = 80;
           
}


            nodes
.add(node);
       
});
       
// once all nodes a loaded fit them to viewport
       topology
.fit();
   
});

Regards,

Ben

Vas Sadvariy

unread,
Nov 23, 2018, 4:30:29 PM11/23/18
to Ben Lockwood, netbox-...@googlegroups.com
Hi Ben,

Happy to hear that you figured it out. Just a suggestion: it is usually a good idea to keep your logic and data separated and try not to hardcode names into your code, at least those you expect to be configurable. There is a config file "topology_config.json" which I added when I realised I need some parameters to be customisable, it is only used now for hiding particular devices, it might be a good idea to try to use it to specify a list of roles you want to display larger. Then you can move individual role names (or better slugs) to the config file and only leave your logic in the .js file. Please use SLUG field instead of NAME just to avoid confusion and issues with special characters. Otherwise I am happy to include this into the project if you can submit a PR.

Alternatively you can reuse 'coordinates' field by adding a third parameter to it: "x;y;size". But in that case you'll have to rewrite save-retrieve coordinates logic, provide UI to adjust size, etc. This solution will give much more granular control over individual devices' sizes but it does not scale well IMO. I'd probably go with option 1 above.

Best regards,
Vas Sadvariy


Mark Carnahan

unread,
Dec 13, 2018, 9:35:38 PM12/13/18
to NetBox
Vas,

Installed the plugin and I really like it.  Any way to include virtual machines as well as devices?  Some of our sites have firewalls that are virtual, so it would be nice to be able to include them and not have to list them as actual devices.

Thanks,

Mark

Vas Sadvariy

unread,
Dec 14, 2018, 5:44:59 AM12/14/18
to mark.c...@gmail.com, NetBox
Hi Mark,

Sure, everything is possible but unfortunately I would not be able to implement it for you. I have not been using Netbox for more than 4 months now as I left the company I originally developed this mod for, and my current company uses internal IPAM solutions.

It should not be difficult at all if you have some knowledge in REST API and JS. You can just see how it is implemented in my module and try to modify it a little bit.

Best regards,
Vas Sadvariy


--
You received this message because you are subscribed to a topic in the Google Groups "NetBox" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/netbox-discuss/MRp0I6nS5xc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to netbox-discus...@googlegroups.com.
To post to this group, send email to netbox-...@googlegroups.com.

Luis N

unread,
Dec 14, 2018, 10:07:51 AM12/14/18
to sadv...@gmail.com, mark.c...@gmail.com, NetBox
What would I need to do to get this topology tree working w/ my current 2.5.1 netbox instance? 

You received this message because you are subscribed to the Google Groups "NetBox" group.
To unsubscribe from this group and stop receiving emails from it, send an email to netbox-discus...@googlegroups.com.

To post to this group, send email to netbox-...@googlegroups.com.

Ben Lockwood

unread,
Dec 14, 2018, 10:12:28 AM12/14/18
to NetBox
Hey Vas,

Is anyone still working on the mod? i've been tinkering with it behind the scenes a lot and long term would like to rebuild it to add more features to it such as having a global topology that would show how sites are interconnected and would allow you to click on a site to open that site where you would see the topology within that site. As well as being able to click on each device to navigate to that devices page in net box. My questions being 1. would you be okay with a take over a month or so down the line, and 2. does anyone else have interest in assisting with this endeavor? I am a huge fan of the mod and would hate to see it die. I'm not going to have much free time for the next few months but would definitely like to continue working on it while i can.

Regards,

Ben

Vas Sadvariy

unread,
Dec 14, 2018, 6:46:35 PM12/14/18
to Ben Lockwood, NetBox
Hi Ben,

Thanks for your interest, I enjoyed working on this mod and using it myself. However, there has been no active support to the module for about half a year because as I've mentioned earlier I do not use Netbox in production anymore and I do not have enough time to work on it in my free time.

As for the contribution to the project, you don't have to ask my permission =) It is an open source project under Apache license, so you are free to fork, modify it the way you see fit and (if you really want to) create a pull request to contribute to the upstream project. I'd happily accept any [sensible] changes and fixes that help to keep the mod operational and compatible with different Netbox versions and its constantly changing API.

If you are interested in taking over I sure can give you write access to the repository but I would probably want to see one or two contributions from you via pull requests first, hope you understand.

Netbox is sure an awesome tool for network engineers, with Jeremy doing a great job to build such a comprehensive model but unfortunately there is not a single chance my current company would adopt it and I will probably stick with them for quite some time, so I am not sure when I would be able to return to this mod, if ever.

Best regards,
Vas Sadvariy


Luca

unread,
Jun 14, 2019, 4:50:09 AM6/14/19
to NetBox
Hi,
i just started to use this powerful plugin, thanks to develop it!!

I would to know if somebody knows ho to show on topology just interface and not all cable; I mean, in my device I added also patch panel, so on topology i can see all rearport connection of PP, but if i hide them, i can't see the link device to device and so the interface.

some one knows how to show just interface?

thank.
To unsubscribe from this group and all its topics, send an email to netbox-...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages