From cbe55e5dd3d38e00025985c6fff248ace8f0f326 Mon Sep 17 00:00:00 2001
From: Brano Zarnovican <zarnovican@gmail.com>
Date: Fri, 6 May 2011 16:34:57 +0100
Subject: [PATCH] added system_post_ip_alloc.py plugin to auto-allocate IPs by cobbler

---
 cobbler/modules/system_post_ip_alloc.py |   97 +++++++++++++++++++++++++++++++
 cobbler/settings.py                     |    1 +
 installer_templates/settings.template   |   11 ++++
 3 files changed, 109 insertions(+), 0 deletions(-)
 create mode 100644 cobbler/modules/system_post_ip_alloc.py

diff --git a/cobbler/modules/system_post_ip_alloc.py b/cobbler/modules/system_post_ip_alloc.py
new file mode 100644
index 0000000..7c48ee6
--- /dev/null
+++ b/cobbler/modules/system_post_ip_alloc.py
@@ -0,0 +1,97 @@
+"""
+This module allow Cobbler to auto-allocate IP to newly created hosts.
+If the IP address is set to '0.0.0.0' by user, then Cobbler will choose
+the first unallocated IP from the pool. VLAN name (from --virt-bridge)
+will determine which pool to allocate from.
+
+Example:
+/etc/cobbler/settings:
+ip_auto_alloc: true
+ip_pool:
+    vlan100: 10.10.100.20 - 10.10.100.250
+    vlan101: 10.10.101.20 - 10.10.101.250
+
+cobbler system add --name $host --hostname $host --profile Fedora14-kvm --gateway=10.10.100.1
+cobbler system edit --name $host --interface=eth0 --virt-bridge=vlan100 \
+    --ip=0.0.0.0 --subnet=255.255.255.0 --dns-name=${host}.example.com --static=yes
+cobbler system edit --name $host --interface=eth1 --virt-bridge=vlan101 \
+    --ip=0.0.0.0 --subnet=255.255.255.0 --dns-name=${host}-mgmt.example.com --static=yes
+
+"""
+
+# this module is loaded only if IP alloc is needed (provided by 'python-IPy' package)
+#import IPy
+
+from cobbler.cexceptions import CX
+
+def register():
+   # this string determines, what type of plugin this is.."
+   return '/var/lib/cobbler/triggers/add/system/post/*'
+
+def already_assigned_ips(api):
+    """return a set of all IPs used in Cobbler DB"""
+    import IPy
+
+    assigned_ips = set()
+    for s in api.systems():
+        for (name, interface) in s.interfaces.iteritems():
+            ip = interface['ip_address']
+            if len(ip) > 0:
+                assigned_ips.add(IPy.IP(ip).ip)
+
+    return assigned_ips
+
+def alloc_ip(api, vlan):
+    """find and return an unsued IP in a pool designated by 'vlan'"""
+
+    try:
+        import IPy
+    except ImportError:
+        raise CX('Python module "IPy" not found, please install "python-IPy" package')
+
+    # take ip_pool entry (from settings) corresponding to 'vlan'
+    ip_pool = api.settings().ip_pool
+    if vlan not in ip_pool:
+        raise CX('No pool is defined for vlan %s (/etc/cobbler/settings)' % vlan)
+
+    pool_str = ip_pool[vlan]
+    try:
+        # parse pool entry, expected format "X.X.X.X - Y.Y.Y.Y" (both must be valid IPs)
+        (start_ip, end_ip) = pool_str.replace(' ', '').split('-')
+        start_num = IPy.IP(start_ip).ip
+        end_num = IPy.IP(end_ip).ip
+    except Exception, e:
+        raise CX('Error parsing the pool "%s" for vlan %s' % (pool_str, vlan))
+
+    assigned_ips = already_assigned_ips(api)
+
+    # iterate over all IPs in the pool, find first one that's unsued
+    for i in range(start_num, end_num+1):
+        if i not in assigned_ips:
+            return str(IPy.IP(i))
+    else:
+        raise CX('No free IP available in pool for VLAN %s' % vlan)
+
+def run(api, args, logger):
+
+    # skip plugin if disabled
+    settings = api.settings()
+    if not str(settings.ip_auto_alloc).lower() in ['1', 'yes', 'y', 'true']:
+        return 0
+
+    hostname = args[0]
+    system = api.find_system(hostname)
+
+    # find any interace of 'this' host with IP == '0.0.0.0'
+    for (name, interface) in system.interfaces.iteritems():
+        if interface['ip_address'] == '0.0.0.0':
+            vlan = interface.get('virt_bridge', '')
+            if vlan == '':
+                raise CX('Cannot allocate IP, vlan is not set for interface %s' % name)
+
+            newip = alloc_ip(api, vlan)
+            system.set_ip_address(newip, name)
+            api.serialize()         # make sure that the change is saved to JSON config file
+
+    return 0
+
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 2216a9e..0ea33f3 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -54,6 +54,7 @@ DEFAULTS = {
     "func_master"                 : "overlord.example.org",
     "func_auto_setup"             : 0,
     "http_port"                   : "80",
+    "ip_auto_alloc"               : "false",
     "isc_set_host_name"           : 0,
     "ldap_server"                 : "grimlock.devel.redhat.com",
     "ldap_base_dn"                : "DC=devel,DC=redhat,DC=com",
diff --git a/installer_templates/settings.template b/installer_templates/settings.template
index 335c320..70ddc8b 100644
--- a/installer_templates/settings.template
+++ b/installer_templates/settings.template
@@ -414,3 +414,14 @@ safe_templating_whitelist:
    - silent
    - slurp
    - raw
+
+# Allow Cobbler to auto-allocate IP to newly created hosts.
+# If the IP address is set to '0.0.0.0' by user, then Cobbler will choose
+# the first unallocated IP from the pool below. VLAN name (from --virt-bridge)
+# will determine which pool to allocate from.
+
+#ip_auto_alloc: true
+#ip_pool:
+#    vlan100: 10.10.100.20 - 10.10.100.250
+#    vlan101: 10.10.101.20 - 10.10.101.250
+
-- 
1.6.4.4

