Header Shadow Image


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:

GetAutoNet-IPAM-Driver-OpenNebula-Final.jpg

 

GetAutoNet-IPAM-Driver-OpenNebula-Options-Page.jpg

 

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:

https://i2.wp.com/www.microdevsys.com/WordPressImage/GetAutoNet.py-Executable-Link-Design.jpg?ssl=1Notice 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!


     
  Copyright © 2003 - 2013 Tom Kacperski (microdevsys.com). All rights reserved.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License