Possible to auto-bind all DHCP clients or L2 neighbors?

Started by Millenium7, February 15, 2021, 03:15:42 AM

Previous topic - Next topic

Millenium7

In an effort to reduce administrative overhead, i'm curious if its possible to automatically bind nodes to a folder from a seed router?
Most of our sites consist of a single distribution router that have various equipment connected to it. Switches, radios, UPS, clients etc

Everything at that site gets an IP address from that distribution router and thus all routing to reach it goes through that distribution router as well
Is it possible to automatically bind all discovered devices connected at Layer2 via that seed router? That way we can create 1 folder per physical site and all new equipment that gets added would automatically get added into that folder

Hopefully we could then expand that functionality further so all of those devices use that seed router as a dependent so if the router is unreachable we don't get spammed with Down alerts/notifications (since all equipment would be unreachable anyway)

Victor Kirhenshtein

There are multiple ways of doing this. Below is auto bind script that illustrates one approach:


if (not ($container->name match "^Site:(.*)"))
   return false;
router = FindObject($1);
if (router == null)
   return false;
for(rp : router->parents)
{
   if (classof(rp) == "Subnet")
   {
for(np : $node->parents)
   if (np->id == rp->id)   // Same object
      return true;
   }
}
return false;


This script assumes that container is called "Site:RouterName", so it extracts name of the router object from own name. You can choose whatever method of router identification that suits you best. Then it checks all subnets this router belongs to, and binds all nodes from those subnets (including itself). For practical use you may have to add additional filters on what subnets to consider.

Best regards,
Victor

Millenium7

#2
Thanks, though its not working for me just yet
It is working I had the name slightly wrong

On a side tangent. How exactly do I go about troubleshooting scripts and syntax 'effectively'? It's something i've constantly struggled with NetXMS script writing because I can't progressively step through and troubleshoot all the variables and operations 1 by 1, but maybe there is a way to do this?
For instance the very first line

if (not ($container->name match "^Site:(.*)"))

How do I troubleshoot this by seeing what $container is returning? and what (.*) is? (I know what it is but assume I just want to see the output for troubleshooting purposes) This would HUGELY help me troubleshoot it
I thought I could just put commands above it like
trace(0,$container);
trace(0,$node);
But nothing shows up in Event Monitor (where else could I see it?)
The only way i've done this in the past is using 'Execute Server Script' on a node/container and I use 'println' to give me some output and I work from there. But this doesn't work in a live script, and sometimes that's the only method. Like right now because it relies on variables like $container which don't exist when using 'Execute Server Script'

To put it simply: How do you go about troubleshooting your scripts? Assume I am doing everything completely wrong, can you please tell me exactly where to go and what to do to step through a script line by line and troubleshoot it correctly.
I can figure out the syntax and fumbly my way through if I know what all the variables are doing, but if I don't have that then I just spend an hour guessing randomly hoping the thing works, and if it doesn't I have no idea where its failing when it could be as simple as using $1 instead of $node or vice-versa

Millenium7

#3
Whew, finally after several hours of fighting the syntax, I stumbled my way across the line

I was also confused by your first line, why is it even there? I get that the match statement is to use a regex to extract $1 as the router name, but wouldn't it always return true? as its just tested itself against..... itself, right?

Anyway here's the script I finally came up with. I'm using a custom attribute on the folder/container itself called 'SeedRouter' and I put the ID of the router I want to use as the seed object. This fits our purposes better than a name (Since i've configured NetXMS to automatically refresh names if the router's name has been changed, that would screw up this auto binding)

t = GetCustomAttribute($container, "SeedRouter");
if (t == null) return false;
SeedRouter = FindObject(t);
if (SeedRouter == null) return false;
trace(0,"Custom Attribute = ".t); // Debug, show value of 'SeedRouter' in container
trace(0,"Seed Router name = ".SeedRouter->name); // Debug, show name of router matching that ID
if ($node == SeedRouter->name) return true; // If node being tested matches seed, return true and save some CPU cycles
for(rp : SeedRouter->parents)
{
   if (classof(rp) == "Subnet")
   {
for(np : $node->parents)
   if (np->id == rp->id)   // Same object
      return true;
   }
}
return false;


The only way I finally got any useful debugging was to kill the netxmsd service and re-run it as an application in Linux. Then trace level 0 worked to display output in the SSH window. However this clearly isn't the most practical way to do it as I don't want to restart the instance every time I start to work on a script
I use the web interface and I can see it is missing the Console output window. I presume I could have also used that if it was there? Problem is the latest Windows Management Binary is broken and errors out on launch (tried on 2 different PC's)

Millenium7

1 downside to both scripts however
When discovering/adding a new node to NetXMS. It appears to bind to all of the folders using these scripts. So something is causing an immediate match upon the first discovery poll....

Victor Kirhenshtein

Hi,

some comments in no particular order.

1. Why use regexp within if:

if (not ($container->name match "^Site:(.*)"))

It could be useful if you put this code into library and re-use in multiple containers. If you by mistake call it on container with wrong naming scheme it will just exit immediately.

2. trace() function writes to server log file, so you can just monitor netxmsd log. First argument is debug level, with 0 being "info" level message (always logged). If you want to show something in event monitor you can create new event (for example call it SCRIPT_OUTPUT) with message field set to %1, and then use the following code to trace:

PostEvent($object, "SCRIPT_OUTPUT", null, "Debug output here");
[code]
New event will appear in event monitor with message set to whatever debug message you put in a call.

3. Line
[code]
if ($node == SeedRouter->name)

will never work - $node is a node object, and SeedRouter->name is a string. You should use

if ($node->id == SeedRouter->id)


4. I mostly use "execute server script" for script debugging. For additional objects like $container in this case I just add temporary line like

$container = FindObject("test container");


5. It is possible to dump all attributes and methods of an object. For example, to dump all attributes of $node:

for(a : $node->__class->attributes)
   println(a . " = " . $node->__get(a));

or all methods:

for(m : $node->__class->methods)
   println(m);


Best regards,
Victor

Millenium7

Excellent, that helps a lot, thank you

I would like to see a better write-up in the wiki/documentation (or even a pinned post here, or a separate scripting section) that goes further into explaining the scripting language and actual applications of it, with much more samples and details on how/why

Like what you posted

Quote from: Victor Kirhenshtein on February 16, 2021, 10:04:49 AM

5. It is possible to dump all attributes and methods of an object. For example, to dump all attributes of $node:

for(a : $node->__class->attributes)
   println(a . " = " . $node->__get(a));

or all methods:

for(m : $node->__class->methods)
   println(m);



That is immensely helpful, and is foundation level stuff that should be explained in the documentation to help navigate around what commands to use, but how/why/when to use them
Same thing with debug output, that's been my biggest hurdle with NetXMS and so many hours lost trying to get things working. The commands are written up with a few examples, but not enough attention to actually putting them into practice and how/why you would use them, and most importantly a write-up on debugging and troubleshooting to show people where to go when something doesn't work
I often feel like i've been given a hammer and some nails, told how to use them, but the lights are off so the best I can do is guess where they should go. Having a few torches to help light the room up would be nice

Millenium7

Found the problem with new nodes being added automatically in wrong site

That's actually not the problem. It was that NetXMS was grouping /32 loopback addresses into a /24 subnet which contained a lot of other routers. I deleted the subnet (maybe a misconfiguration earlier?) and that solved the issue

I've also tested your code samples above and its immensely helpful in drilling through possible variables, lot in there I didn't even know about, now it makes significantly more sense and i'll be able to craft some better scripts. Thank you