GetAutoNet: Automatic IP Range / VLAN segment Discovery Tool.
GetAutoNet
GetAutoNet is a IP and IP range discovery tool for OpenNebula using nmap. The returned free IP list is checked against a defined list of DNS servers to ensure IP's or ranges of IP's returned are not allocated to offline machines.
Runtime
Register a network:
$ ./register_address_range register-address-range.xml
AR = [
IPAM_MAD = "GetAutoNet",
TYPE = "IP4",
IP = "10.0.0.101",
SIZE = "154",
NETWORK_ADDRESS = "10.0.0.0",
NETWORK_MASK = "255.255.255.0",
GATEWAY = "10.0.0.1",
DNS = "192.168.0.44 192.168.0.45 192.168.0.154 192.168.0.155 192.168.0.224 192.168.0.220 192.168.0.221",
IPAM_ATTR = "10.0.0.255",
OTHER_IPAM_ATTR = "mws.mds.xyz",
MAC = "AA:BB:CC:DD:00:01"
]
$
Get single IP address:
$ ./get_single get-single-address.xml
AR = [
IP = "10.0.0.101",
SIZE = "1"
]
$
Sample input file:
$ cat register-address-range.xml
<IPAM_DRIVER_ACTION_DATA>
<AR>
<TYPE>IP4</TYPE>
<IP>10.0.0.1</IP>
<MAC>AA:BB:CC:DD:00:01</MAC>
<SIZE>255</SIZE>
<NETWORK_ADDRESS>10.0.0.117</NETWORK_ADDRESS>
<NETWORK_MASK>255.255.255.0</NETWORK_MASK>
<GATEWAY>10.0.0.1</GATEWAY>
<DNS>192.168.0.111 192.168.0.112 192.168.0.113 192.168.0.114 192.168.0.115 192.168.0.116 192.168.0.117</DNS>
<GUEST_MTU>1500</GUEST_MTU>
<SEARCH_DOMAIN>abc.dom xyz.dom private.xyz.dom</SEARCH_DOMAIN>
<LOWER_LIMIT>100</LOWER_LIMIT>
<UPPER_LIMIT>255</UPPER_LIMIT>
</AR>
</IPAM_DRIVER_ACTION_DATA>
$
$ cat allocate-address-range.xml
<IPAM_DRIVER_ACTION_DATA>
<AR>
<TYPE>IP4</TYPE>
<IP>10.0.0.1</IP>
<MAC>AA:BB:CC:DD:00:01</MAC>
<SIZE>255</SIZE>
<NETWORK_ADDRESS>10.0.0.117</NETWORK_ADDRESS>
<NETWORK_MASK>255.255.255.0</NETWORK_MASK>
<GATEWAY>10.0.0.1</GATEWAY>
<DNS>192.168.0.111 192.168.0.112 192.168.0.113 192.168.0.114 192.168.0.115 192.168.0.116 192.168.0.117</DNS>
<GUEST_MTU>1500</GUEST_MTU>
<SEARCH_DOMAIN>abc.dom xyz.dom private.xyz.dom</SEARCH_DOMAIN>
<LOWER_LIMIT>100</LOWER_LIMIT>
<UPPER_LIMIT>255</UPPER_LIMIT>
</AR>
<ADDRESS>
<IP>10.0.0.117</IP>
<SIZE>44</SIZE>
<MAC>AA:BB:CC:DD:EE:FF:01:01</MAC>
</ADDRESS>
</IPAM_DRIVER_ACTION_DATA>
$
RPM Build Notes
To modify the code and roll your own RPM, first pull the repo down:
git clone https://github.com/tomkcpr/GetAutoNet.git
then simply issue the following rpmbuild commands:
[root@one01 SPECS]# pwd
/root/GetAutoNet/rpmbuild/SPECS
[root@one01 SPECS]# rpmbuild –target noarch -bb GetAutoNet.spec
Screenshots
A few screenshots of the working driver:
Code Requirements
OpenNebula doesn't allow passing parameters through standard shell options at this time. In addition, the script needs to accept:
1) XML file input.
2) Base64 encoded strings.
3) Unencoded XML based input.
To suffice all three conditions, this tool will attempt to detect the type of parameter passed based on the arguments used.
If this wasn't enough, a number of scripts needed to be called, each performing a specific OpenNebula function:
get_single
free_address
get_address
allocate_address
unregister_address_range
register_address_range
In order to satisfy calling each function, a copy of or wrapper code would have been required. This would carry a heavy maintenance cost due to having numerous scripts. Consistency through the various scripts would also have to be maintained since all would share some common functionality to determine said ranges. Multiple separate components instead of one monolithic script are still preferred but this is left for another version once a suitable easy-to-maintain design is decided on.
Lastly, the script would need to run from the oneadmin user.
Architecture Decision and Design
To satisfy the above requirements, a single script, GetAutoNet.py is being used at this time. Numerous symbolic links point to the same GetAutoNet.py executable. The action is determined based on the sys.argv[0] parameter containing the executable symbolic link used to call the code. Below is an example:
[oneadmin@one01 GetAutoNet]$ ls -altri
total 140
134569729 drwxr-x—. 6 oneadmin oneadmin 69 Feb 29 23:07 ..
135607419 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 get_single -> GetAutoNet.py
135607420 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 free_address -> GetAutoNet.py
135607421 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 get_address -> GetAutoNet.py
135607422 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 allocate_address -> GetAutoNet.py
135607423 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 unregister_address_range -> GetAutoNet.py
135632640 lrwxrwxrwx. 1 oneadmin oneadmin 13 Feb 29 23:07 register_address_range -> GetAutoNet.py
136694338 -rw-r—–. 1 oneadmin oneadmin 546 Mar 15 14:22 register-address-range.xml
136690314 -rw-r—–. 1 oneadmin oneadmin 644 Mar 16 01:09 allocate-address-range.xml
136690315 -rw-r—–. 1 oneadmin oneadmin 546 Mar 16 01:55 get-single-address.xml
136694339 -rw-r—–. 1 oneadmin oneadmin 644 Mar 16 01:57 free-address-range.xml
136694342 -rw-r—–. 1 oneadmin oneadmin 585 Mar 16 02:01 get-address-range.xml
136694340 -rwxr-xr-x. 1 oneadmin oneadmin 32199 Mar 16 02:03 GetAutoNet.py
135607191 drwxr-x—. 2 oneadmin oneadmin 4096 Mar 16 02:03 .
135679218 -rw-r–r–. 1 oneadmin oneadmin 86016 Mar 16 02:03 .GetAutoNet.py.swp
[oneadmin@one01 GetAutoNet]$ ./get_single get-single-address.xml
AR = [
IP = "10.0.0.101",
SIZE = "1"
]
[oneadmin@one01 GetAutoNet]$ ./free_address free-address-range.xml
[oneadmin@one01 GetAutoNet]$ echo $?
0
[oneadmin@one01 GetAutoNet]$ ./get_address get-address-range.xml
ADDRESS = [ IP = “10.0.0.101”, SIZE = “33” ]
[oneadmin@one01 GetAutoNet]$ ./allocate_address allocate-address-range.xml
[oneadmin@one01 GetAutoNet]$ echo $?
0
[oneadmin@one01 GetAutoNet]$ ./unregister_address_range register-address-range.xml
[oneadmin@one01 GetAutoNet]$ echo $?
0
[oneadmin@one01 GetAutoNet]$ ./register_address_range register-address-range.xml
AR = [
IPAM_MAD = "GetAutoNet",
TYPE = "IP4",
IP = "10.0.0.101",
SIZE = "154",
NETWORK_ADDRESS = "10.0.0.0",
NETWORK_MASK = "255.255.255.0",
GATEWAY = "10.0.0.1",
DNS = "192.168.0.44 192.168.0.45 192.168.0.154 192.168.0.155 192.168.0.224 192.168.0.220 192.168.0.221",
IPAM_ATTR = "10.0.0.255",
OTHER_IPAM_ATTR = "mws.mds.xyz",
MAC = "AA:BB:CC:DD:00:01"
]
[oneadmin@one01 GetAutoNet]$
Image view:
Notice how the result above differs when using different symbolic links to execute GetAutoNet.sh . The script determines the desired function by the command line executable used. For example, the register_address_range caller name is detected by searching for said name in sys.argv[0] :
862 # Register an address range of IP's
863 if re.search(r'./register_address_range', sys.argv[0]):
864 ga.logmsg("main(): Register an address range of IP's. Calling ga.getrange()(" + sys.argv[0] + "): ")
865 retval=ga.getrange()
866 ga.logmsg("main(): retval = " + str(retval))
867 return retval
Once detected, the script performs given action as if register_address_range was a separate script.
Classes and Functions
The code is made up of a single Class and numerous functions. Below is a list with a short description:
class GetAutoNet():
def logmsg(self, msg): – Log Script Messages
def __init__(self): – Constructor
def __init__(self, log): – Constructior w/ Logger option.
def tocidr(self, netmask): – Convert Netmask from 255.255.255.0 to CIDR format.
def nmapScan(self, vlan, netmask): – Run an nmap scan against the VLAN
def dnsLookup(self): – Perform DNS lookup of IP's against a set of DNS servers.
def isBase64(self,sb): – Determine if passed parameter is a Base64 encoded string.
def getAddress(self): – Get single or range of addresses (Core Class Function)
def getsingle(self): – Get a single address
def getrange(self, brief = 0): – Get range of IP's. Print in one of two ways, brief(1) or brief(2).
def convert(self,lst): – Convert a list to a dictionary for lookups.
def freeAddress(self): – Free a given address or address range.
def main(): – Main code function. Class GetAutoNet instantiated here.
Logging
The script attempt to log much of what it does. The log file that is created is:
/var/log/GetAutoNet/GetAutoNet.log
When reporting issues, ensure you submit a redacted copy of the above log file for analysis. The log can be cleared to create a fresh per-session log file simplifying session troubleshooting.
Troubleshooting
Potential issues in the code can be debugged using the command line. Similar to the above example, various links can be called executing the script to determine faults. Additionally, the code can be executed with the two additional formats such as the base64 format, to pinpoint specific issues. For example:
$ ./register_address_range PElQQU1fRFJJVkVSX0FDVElPTl9EQVRBPjxBUj48RE5TPjwhW0NEQVRBWzE5Mi4xNjguMC40NCAxOTIuMTY4LjAuNDUgMTkyLjE2OC4wLjE1NCAxOTIuMTY4LjAuMTU1IDE5Mi4xNjguMC4yMjQgMTkyLjE2OC4wLjIyMCAxOTIuMTY4LjAuMjIxXV0+PC9ETlM+PElQPjwhW0NEQVRBWzEwLjAuMC4xMDBdXT48L0lQPjxJUEFNX01BRD48IVtDREFUQVtHZXRBdXRvTmV0XV0+PC9JUEFNX01BRD48TUFDPjwhW0NEQVRBWzExOjEyOjEzOjE0OjAxOjAxXV0+PC9NQUM+PE5FVFdPUktfQUREUkVTUz48IVtDREFUQVsxMC4wLjAuMF1dPjwvTkVUV09SS19BRERSRVNTPjxORVRXT1JLX01BU0s+PCFbQ0RBVEFbMjU1LjI1NS4yNTUuMF1dPjwvTkVUV09SS19NQVNLPjxTSVpFPjwhW0NEQVRBWzE1NV1dPjwvU0laRT48VFlQRT48IVtDREFUQVtJUDRdXT48L1RZUEU+PC9BUj48QUREUkVTUz48TUFDLz48SVAvPjxJUDZfR0xPQkFMLz48SVA2X1VMQS8+PElQNi8+PFNJWkUvPjwvQUREUkVTUz48L0lQQU1fRFJJVkVSX0FDVElPTl9EQVRBPg==
AR = [
IPAM_MAD = "GetAutoNet",
TYPE = "IP4",
IP = "10.0.0.101",
SIZE = "153",
NETWORK_ADDRESS = "10.0.0.0",
NETWORK_MASK = "255.255.255.0",
GATEWAY = "",
DNS = "192.168.0.44 192.168.0.45 192.168.0.154 192.168.0.155 192.168.0.224 192.168.0.220 192.168.0.221",
IPAM_ATTR = "10.0.0.254",
OTHER_IPAM_ATTR = "",
MAC = "11:12:13:14:01:01"
]
$
Notice how passing the Base64 encoded string has the same result as passing a valid file name with unencoded XML argument.
Future Plans
Depending on demand, the following updates are planned:
1) Separate the code into multiple individual dependent code components instead of a single monolithic program.
2) Promote to the master branch once sufficient testing has been completed.
3) Update for Ubuntu
4) Test on OpenNebula 5.10.X
Cheers!