Back to the main page

DHCP reservation for Linux, Solaris, AK

Intro

This is bigger reservation then this page . The design is almost same, the bigger tool supports Linux and Solaris 10, 11 and AK (basically Solaris for ZFS appliance), and should support more sites, hence there is site dedicated configuration file to specify Cobbler and Jumpstart/AI (Automated Installer) server for that specific site.

Design

Implementation

Files

List of supported subnets (location: sca)

File sca-subnets.txt reads something like:
20.162.48.0/24
20.162.49.0/24
...shortened ...
20.169.131.0/24

Site config file (location: sca)

File sca.cfg reads something like:
# This is config file for SCA DHCP reservation
COBBLER_SERVER = 'ca-cobbler-sca.domain.com'   # next-server for OL/OVS/Linux
CAINSTALL_SERVER = 'ca-install-sca.domain.com'  # install server for Sol/AK

Module lib/dhcp_cfg.py


" Module to create DHCP config file for Cobbler and ca-install clients"
# The module name is .py
# When import, use only : ex.
# import  
# Use sys.path.append("/path/to/module") if needed
# ------------------------------------------------------
import os
import socket
import sys
import re

global DHCPCFGDIR
DHCPCFGDIR = "/etc/dhcp/clients/"

# --------------------------
# Cobbler system
# --------------------------
class COBBLER_SYSTEM(object):
    """
    Blueprint for DHCP Cobbler system's config file
    Attributes:
       1. loc (string, location is hardcoded in script that imports this module)
       2. hostname (string, user input)
       3. mac (string, user input)
       4. ip (string, calculated)
       5. router (string, calculated)
       6. bootfile (string, user input): default is None object
    """
 
    def __init__(self, loc, hostname, mac, ip, router, bootfile=None):
       """
       Initialize object whos attributes are collection of data
       used to create DHCP config file for Cobbler client
       """
       self.loc = loc
       self.hostname = hostname
       self.mac = mac
       self.ip = ip
       self.router = router
       self.bootfile = bootfile
       global CFG_COBBLER_SYSTEM
       CFG_COBBLER_SYSTEM = DHCPCFGDIR + self.hostname 
       # Get values from config file, each loc has its own dir/cfg file
       # parent directory is os.path.join(sys.path[0], os.pardir)
       LOCATION_CFGFILE = (os.path.join(sys.path[0], os.pardir) + "/" + self.loc + "/" + self.loc + ".cfg")
       try:
           execfile(LOCATION_CFGFILE, globals())
       except IOError as err:
           sys.exit("IOError: {0}".format(err))
       global cobbler_server_ip
       cobbler_server_ip=socket.gethostbyname(COBBLER_SERVER)   # IP of Cobbler server

    # ---------------------------------------------------------------
    # this is of you want to manipulate filename attribute of an object
    # ---------------------------------------------------------------
    @property
    def bootfile(self):
       """ Get 'bootfile' property/value """
       return self._bootfile

    @bootfile.setter
    def bootfile(self, value):
       """ Set value to 'bootfile' """
       self._bootfile = value

    @bootfile.deleter
    def bootfile(self):
       """ Delete 'bootfile' """
       del self._bootfile
    # ---------------------------------------------------------------

    def create_cfg_file(self):
        """ Creates config file """
        print ("DHCP reservation has been created: " + CFG_COBBLER_SYSTEM)
        try: 
            if self.bootfile != None:
                f = open(CFG_COBBLER_SYSTEM, "w+")
                f.write("host " + self.hostname + " {\n")
                f.write("\thardware ethernet " + self.mac + " ;\n")
                f.write("\tfixed-address " + self.ip + " ;\n")
                f.write("\toption routers " + self.router + " ;\n")
                f.write("\tnext-server " + cobbler_server_ip + " ;\n")
                f.write("\tfilename " + "\"" + str(self.bootfile) + "\"" + " ;\n")
                f.write("\t }\n")
                f.close()
            else:
                f = open(CFG_COBBLER_SYSTEM, "w+")
                f.write("host " + self.hostname + " {\n")
                f.write("\thardware ethernet " + self.mac + " ;\n")
                f.write("\tfixed-address " + self.ip + " ;\n")
                f.write("\toption routers " + self.router + " ;\n")
                f.write("\tnext-server " + cobbler_server_ip + " ;\n")
                f.write("\t }\n")
                f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

    def remove_cfg_file(self):
        """ Removes config file """
        try:
            os.remove(CFG_COBBLER_SYSTEM)
            print ("File " + CFG_COBBLER_SYSTEM + " is removed!")
        except IOError as err:
            print("IOError: {0}".format(err))

    def read_cfg_file(self):
        """ Prints config file """
        print ("Reading file " + CFG_COBBLER_SYSTEM) 
        try:
            f = open(CFG_COBBLER_SYSTEM, "r")
            print f.read()
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

# --------------------------
# Solaris 11 system
# --------------------------
class S11_SYSTEM(object):
    """
    Blueprint for Solaris 11 client's DHCP config file
    Attributes:
       1. loc (string, location is hardcoded in script that imports this module)
       2. hostname (string, user input)
       3. mac (string, user input)
       4. ip (string, calculated)
    """

    def __init__(self, loc, hostname, mac, ip):
       """
       Initialize object whos attributes are collection of data
       used to create DHCP config file for ca-install client
       """
       self.loc = loc
       self.hostname = hostname
       self.mac = mac
       self.ip = ip
       global CFG_S11_SYSTEM
       CFG_S11_SYSTEM = DHCPCFGDIR + self.hostname 
       # Get values from config file, each loc has its own dir/cfg file
       # parent directory is os.path.join(sys.path[0], os.pardir)
       LOCATION_CFGFILE = (os.path.join(sys.path[0], os.pardir) + "/" + self.loc + "/" + self.loc + ".cfg")
       try:
           execfile(LOCATION_CFGFILE, globals())
       except IOError as err:
           sys.exit("IOError: {0}".format(err))
       global cainstall_ip
       cainstall_ip=socket.gethostbyname(CAINSTALL_SERVER)   # IP of ca-install server

    def create_cfg_file(self):
        """ Creates config file """
        print ("DHCP reservation has been created: " + CFG_S11_SYSTEM)
        client_id = "01" + re.sub(":","",self.mac).upper() 
        try:
            f = open(CFG_S11_SYSTEM, "w+")
            f.write("host " + self.hostname + " { \n")
            f.write("\thardware ethernet " + self.mac + " ;\n")
            f.write("\tfixed-address " + self.ip + " ;\n")
            f.write("\tnext-server " + cainstall_ip + " ;\n")
            f.write("\tif option arch = 00:00 { \n")
            f.write("\t\tfilename \"" + client_id + ".bios" + "\";\n")  
            f.write("\t} else if option arch = 00:07 { \n")
            f.write("\t\tfilename \"" + client_id + ".uefi" + "\";\n")   
            f.write("\t} else { \n")
            f.write("\t\tfilename \"http://" + cainstall_ip + ":5555/cgi-bin/wanboot-cgi\" ;\n") 
            f.write("\t\t }\n")
            f.write("\t }\n")
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

    def remove_cfg_file(self):
        """ Removes config file """
        try:
            os.remove(CFG_S11_SYSTEM)
            print ("File " + CFG_S11_SYSTEM + " is removed!")
        except IOError as err:
            print("IOError: {0}".format(err))

    def read_cfg_file(self):
        """ Prints config file """
        print ("Reading file " + CFG_S11_SYSTEM)
        try:
            f = open(CFG_S11_SYSTEM, "r")
            print f.read()
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

# -----------------------------
# Solaris 10 system x84
# -----------------------------
class S10_SYSTEM_X86(object):
    """
    Blueprint for Solaris 10 x86 client's DHCP config file
    Attributes:
       1. loc (string, location is hardcoded in script that imports this module)
       2. hostname (string, user input)
       3. mac (string, user input)
       4. ip (string, calculated)
    """

    def __init__(self, loc, hostname, mac, ip):
       """
       Initialize object whos attributes are collection of data
       used to create DHCP config file for ca-install client
       """
       self.loc = loc
       self.hostname = hostname
       self.mac = mac
       self.ip = ip
       global CFG_S10_SYSTEM_X86
       CFG_S10_SYSTEM_X86 = DHCPCFGDIR + self.hostname
       # Get values from config file, each loc has its own dir/cfg file
       # parent directory is os.path.join(sys.path[0], os.pardir)
       LOCATION_CFGFILE = (os.path.join(sys.path[0], os.pardir) + "/" + self.loc + "/" + self.loc + ".cfg")
       try:
           execfile(LOCATION_CFGFILE, globals())
       except IOError as err:
           sys.exit("IOError: {0}".format(err))
       global cainstall_ip
       cainstall_ip=socket.gethostbyname(CAINSTALL_SERVER)   # IP of ca-install server

    def create_cfg_file(self):
        """ Creates config file """
        print ("DHCP reservation has been created: " + CFG_S10_SYSTEM_X86)
        client_id = "01" + re.sub(":","",self.mac).upper()
        try:
            f = open(CFG_S10_SYSTEM_X86, "w+")
            f.write("host " + self.hostname + " { \n")
            f.write("\thardware ethernet " + self.mac + " ;\n")
            f.write("\tfixed-address " + self.ip + " ;\n")
            f.write("\tfilename \"" + client_id + "\" ;\n")
            f.write("\tnext-server " + cainstall_ip + " ;\n")
            f.write("\t }\n")
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

    def remove_cfg_file(self):
        """ Removes config file """
        try:
            os.remove(CFG_S10_SYSTEM_X86)
            print ("File " + CFG_S10_SYSTEM_X86 + " is removed!")
        except IOError as err:
            print("IOError: {0}".format(err))

    def read_cfg_file(self):
        """ Prints config file """
        print ("Reading file " + CFG_S10_SYSTEM_X86)
        try:
            f = open(CFG_S10_SYSTEM_X86, "r")
            print f.read()
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))


# ---------------
# AK system
# ---------------
class AK_SYSTEM(object):
    """
    Blueprint for AK client's DHCP config file
    Attributes:
       1. loc (string, location is hardcoded in script that imports this module)
       2. hostname (string, user input)
       3. mac (string, user input)
       4. ip (string, calculated)
    """

    def __init__(self, loc, hostname, mac, ip):
       """
       Initialize object whos attributes are collection of data
       used to create DHCP config file for ca-install client
       """
       self.loc = loc
       self.hostname = hostname
       self.mac = mac
       self.ip = ip
       global CFG_AK_SYSTEM
       CFG_AK_SYSTEM = DHCPCFGDIR + self.hostname
       # Get values from config file, each loc has its own dir/cfg file
       # parent directory is os.path.join(sys.path[0], os.pardir)
       LOCATION_CFGFILE = (os.path.join(sys.path[0], os.pardir) + "/" + self.loc + "/" + self.loc + ".cfg")
       try:
           execfile(LOCATION_CFGFILE, globals())
       except IOError as err:
           sys.exit("IOError: {0}".format(err))
       global cainstall_ip
       cainstall_ip=socket.gethostbyname(CAINSTALL_SERVER)   # IP of ca-install server

    def create_cfg_file(self):
        """ Creates config file """
        print ("DHCP reservation has been created: " + CFG_AK_SYSTEM)
        client_id = "01" + re.sub(":","",self.mac).upper()
        try:
            f = open(CFG_AK_SYSTEM, "w+")
            f.write("host " + self.hostname + " { \n")
            f.write("\thardware ethernet " + self.mac + " ;\n")
            f.write("\tfixed-address " + self.ip + " ;\n")
            f.write("\tnext-server " + cainstall_ip + " ;\n")
            f.write("\tif option arch = 00:00 { \n")
            f.write("\t\tfilename \"" + client_id + ".bios" + "\";\n")
            f.write("\t} else if option arch = 00:07 { \n")
            f.write("\t\tfilename \"" + client_id + ".uefi" + "\";\n")
            f.write("\t} else { \n")
            f.write("\t\tfilename \"http://" + cainstall_ip + ":5555/cgi-bin/wanboot-cgi\" ;\n")
            f.write("\t\t#option SUNW.SsysidCF \"http://" + cainstall_ip + ":5555/solaris/ak\" ;\n")
            f.write("\t\t }\n")
            f.write("\t }\n")
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

    def remove_cfg_file(self):
        """ Removes config file """
        try:
            os.remove(CFG_AK_SYSTEM)
            print ("File " + CFG_AK_SYSTEM + " is removed!")
        except IOError as err:
            print("IOError: {0}".format(err))

    def read_cfg_file(self):
        """ Prints config file """
        print ("Reading file " + CFG_AK_SYSTEM)
        try:
            f = open(CFG_AK_SYSTEM, "r")
            print f.read()
            f.close()
        except IOError as err:
            print("IOError: {0}".format(err))

if __name__ == '__main__': 

   # Cobbler client test, only when module is run directly !
   print COBBLER_SYSTEM.__doc__
   ca_zdudic = COBBLER_SYSTEM("sca", "ca-zdudic1.domain.com", 
                             "10:2:30:4:5:61", "10.211.22.33", "10.211.0.1", "/path/boot/me/file")
   #ca_zdudic = COBBLER_SYSTEM("sca", "ca-zdudic2.domain.com", "1:21:3:41:5:6", "10.211.22.33", "10.211.0.1")
   print "hostname is " + ca_zdudic.hostname
   print "mac is " + ca_zdudic.mac
   print "boot file is " + str(ca_zdudic.bootfile)
   ca_zdudic.create_cfg_file()
   ca_zdudic.read_cfg_file()
   ca_zdudic.remove_cfg_file()

   # Sol 11 client test
   print S11_SYSTEM.__doc__
   ca_zdudic2 = S11_SYSTEM("sca", "ca-zdudic2.domain.com", "00:ab:cd:ef:22:33", "10.211.11.66")
   print "hostname is " + ca_zdudic2.hostname
   print "mac is " + ca_zdudic2.mac
   ca_zdudic2.create_cfg_file()
   ca_zdudic2.read_cfg_file()
   ca_zdudic2.remove_cfg_file()
   
   # Sol 10 client test
   print S10_SYSTEM_X86.__doc__
   ca_zdudic1 = S10_SYSTEM_X86("sca", "ca-zdudic1.domain.com", "00:ab:cd:ef:22:33", "10.147.24.49")
   ca_zdudic1.create_cfg_file()
   ca_zdudic1.read_cfg_file()
   ca_zdudic1.remove_cfg_file()

Main script sca/dhcp-sca-reserve.py (location: sca)

Note: see variable "LOC"

#!/usr/bin/env python

# SCA DHCP reservation 
# ----------------------
import os
import sys
import getpass
import socket
import netaddr 
import argparse
import ldap
import pwd   # getting real user
import subprocess
from time import gmtime, strftime
import datetime
import logging, logging.handlers
sys.path.append(os.path.abspath(os.path.join(sys.path[0], os.pardir)))  # append parent dir
import lib.dhcp_cfg as dhcp_cfg # import LabOps module for DHCP cfg files creation

# --- LOCATION is uniq ----
LOC = "sca"   
# -------------------------

i_am=getpass.getuser()
if i_am != "root":
    sys.exit(i_am + ", please run this via sudo (otherwise you won't have permissions to complete reservation)")

# even root must use sudo
try:
    realuser = pwd.getpwuid(int(os.getenv('SUDO_UID'))).pw_name
    realuserid = os.getenv('SUDO_UID')
except:
    #SUDO_UID is missing
    sys.exit("Even root is requested to use sudo, please re-run it with sudo.")

# define logging directory structure 
PROGRAM = os.path.basename(sys.argv[0])   # name of this script
LOG_PATH = ("/var/log/" + PROGRAM)        # put together "/var/log/"
if not os.path.exists(LOG_PATH):          # create LOG_PATH if doesn't exists
    os.makedirs(LOG_PATH)
    os.chown(LOG_PATH,-1,580)       # root(-1 means no change):crm for DSEE client
    os.chmod(LOG_PATH,0775)               # drwxrwxr-x

def verify_mac(hwaddr):
    """
    To be used as type for MAC argument
    """
    if not netaddr.valid_mac(hwaddr):
        sys.exit("ERROR: %s is not valid MAC" % hwaddr)
    return hwaddr

def verify_owner(username):
    """
    Check if this is valid DSEE username
    https://www.python-ldap.org/en/python-ldap-3.2.0/reference/ldap.html
    Search filers can be:
    email address: searchFilter = "mail=mickey.mouse@oracle.com" 
    login: searchFilter = "uid=mmouse"
    UID: searchFilter = "uidNumber=123456789"
    """
    DSEE_SRV="dsee-ldap-server.domain.com"  # DSEE server
    baseDN = "dc=domain,dc=com"
    searchScope = ldap.SCOPE_SUBTREE # subtree search
    retrieveAttributes = None
    # create ldap object
    try:
        ldapobject = ldap.initialize('ldap://' + DSEE_SRV)
        ldapobject.protocol_version = ldap.VERSION3
    except ldap.LDAPError as err:
        sys.exit("ldap.LDAPError: {0}".format(err))

    try:
        searchFilter = "uid=" + username
        l_search = ldapobject.search(baseDN, searchScope, searchFilter, retrieveAttributes)
        result_status, result_data = ldapobject.result(l_search, 0)
        if not result_data:
            sys.exit("ERROR: there is no " + username + " in DSEE" )
        else:
            return username
    except ldap.LDAPError as err:
        sys.exit("ldap.LDAPError: {0}".format(err))

# -- argument work
parser = argparse.ArgumentParser(
                                description="Add DHCP cfg file for a system (location: " + LOC + " )",
                                epilog='Brought to you by LabOps')
os = parser.add_mutually_exclusive_group(required=True)
os.add_argument("-l", "--linux", help="Linux install via Cobbler", action="store_true") # store_true for flag, no value
os.add_argument("-i", "--solaris11", help="Solaris 11 install", action="store_true")
os.add_argument("-j", "--solaris10", help="Solaris 10 x86 install (SPARC is not supported)", action="store_true")
os.add_argument("-z", "--ak", help="AK install", action="store_true")
parser.add_argument("-s", "--system", help="System's FQDN", required=True)
parser.add_argument("-m", "--mac", help="System's MAC ( : as delimiter)", type=verify_mac, required=True)
parser.add_argument("-b", "--bootfile", help="Custom boot file, only linux install (it must be in :/tftpboot)")
parser.add_argument("-o", "--owner", help=argparse.SUPPRESS, type=verify_owner)  # hidden option
args = parser.parse_args()
system=args.system   
mac=args.mac
linuxinstall=args.linux
s11install=args.solaris11
s10install=args.solaris10
akinstall=args.ak

# --- Define logging
LOG_FILE = (LOG_PATH + "/" + system + "_" + datetime.datetime.now().strftime("%m-%d-%Y_%Hh%Mm%Ss"))
# create logger (interface that script uses for logging)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create file handler (define log destination)
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILE, when='MIDNIGHT', backupCount=50, utc=False)
# create formatter (define layout of logs)
formatter = logging.Formatter('%(asctime)s:%(levelname)s: %(message)s')
handler.setFormatter(formatter)
# add handler to logger
logger.addHandler(handler)

# start logging
logger.debug("")
logger.debug("START AT : " + strftime("%a, %d %b %Y %H:%M:%S", gmtime()))
logger.debug("Location for a config file: " + LOC)
SUBNETFILE = (sys.path[0] + "/" + LOC + "-subnets.txt")  # location subnet file, in same dir as running script 
logger.debug("Subnet list is from the file " + SUBNETFILE)

def not_whq_pls():
    """
    Check that script is not used on DHCP in WHQ and PLS2.
    These two DHCP servers are under LabOps control,
    and users should not modify anything there.
    """
    if socket.gethostname() == "ca-hq-infra1.domain.com" or socket.gethostname() == "ca-pls-infra1.domain.com":
        logger.debug("ERROR: This can't be run on WHQ or PLS DHCP servers.")
        sys.exit("ERROR: This can't be run on WHQ or PLS DHCP servers.")

# No running in WHQ/PLS
not_whq_pls()

# Log who runs this and on behalf of whom
# compare with i_am, which is basically root
# also check if hidden argument 'owner' is used
if realuser != i_am:    # run by mortal user via sudo
    if not args.owner:
        logger.debug("Run by " + realuser + " (uid: " + realuserid + ") as root, via sudo.")
    else:
        logger.debug(realuser + ", you cannot reserve on behalf of someone else.")
        sys.exit(realuser + ", you cannot reserve on behalf of someone else.")
if realuser == i_am:    # run by root
    if not args.owner:
        logger.debug("Root cannot do this without providing owner of reservation, use <-o DSEE_account>")
        sys.exit("Root cannot do this without providing owner of reservation, use <-o DSEE_account>")
    else:
        logger.debug("Run by root on behalf of " + args.owner)


def bootfile_check():
    """
    Not used, 
    but can be used to check existence of bootfile in Cobbler server 
    """
    if args.bootfile:
        if os.path.isfile("/tftpboot/" + args.bootfile):
            logger.debug("OK: /tftpboot/" + args.bootfile + " exists")
        else:
            logger.debug("ERROR: Cannot find /tftpboot/" + args.bootfile )
            sys.exit("ERROR: Cannot find /tftpboot/" + args.bootfile )

def find_ip():
    """
    Determine IP for given system
    """
    try:
        global ipaddress 	# define global to be used outside of this function
        global systemfqdn 	
        ipaddress = socket.gethostbyname(system)
        logger.debug("OK: " + system + "'s IP address is " + ipaddress)
        systemfqdn = socket.getfqdn(system) 
    except:
        logger.debug("ERROR: " + system + " is not in DNS")
        sys.exit("ERROR: " + system + " is not in DNS")

def subnet_check(ipaddress): 
    """
    Check if IP is in subnet,
    and find router and broadcast address.
    Arguments: 
             1. IP, determined by find_ip()
             2. file (list of subnets), it's hard coded here!
    """
    global default_router
    f = open(SUBNETFILE, 'r')
    ip_ok = False
    try:
        for subnet in f:
            if netaddr.IPAddress(ipaddress) in netaddr.IPNetwork(subnet):
                logger.debug("OK: " + ipaddress + " is on supported " + LOC + " subnet " + str(netaddr.IPNetwork(subnet)))
                default_router = str(netaddr.IPNetwork(subnet).network + 1) # assumption: default router is network IP + 1
                broadcast_ip = str(netaddr.IPNetwork(subnet).broadcast)
                logger.debug("Default router (assumption: network IP + 1): " + default_router)
                logger.debug("Broadcast IP: " + broadcast_ip)
                ip_ok = True
        f.close()
    except:
        logger.debug("ERROR: Cannot analyze " + ipaddress + " and determine subnet and default router")
        sys.exit("ERROR: Cannot analyze " + ipaddress + " and determine subnet and default router")

    if not ip_ok:
        logger.debug("WARNING: " + ipaddress + " is on " + LOC + " subnet not supported on this DHCP!")
        sys.exit("WARNING: " + ipaddress + " is on " + LOC + " subnet not supported on this DHCP!")

def create_cobbler_cfg_file():
    """
    Note: dash (-) & dot (.) can't be used in object name,
          hence we create first systemobject
    """
    systemobject = system.replace("-", "_").replace(".", "_")    
    logger.debug("System's object/ID: " + systemobject) 
    try:
        if args.bootfile:
            systemobject =  dhcp_cfg.COBBLER_SYSTEM(LOC, systemfqdn, mac, ipaddress, default_router, args.bootfile)
            logger.debug("Creating DHCP cfg for Cobbler system (location: " + systemobject.loc + ") with: " + 
                         systemobject.hostname + " " + systemobject.mac + " " + systemobject.router +
                         " " + str(systemobject.bootfile) )
            systemobject.create_cfg_file()
            orig = sys.stdout  # initial stdout
            sys.stdout = open(LOG_FILE, "a")  # want to read cfg file into log 
            logger.debug("Checking the cfg file:")
            systemobject.read_cfg_file()
            sys.stdout.close()
            sys.stdout = orig  # restore initial stdout
        else:
            systemobject =  dhcp_cfg.COBBLER_SYSTEM(LOC, systemfqdn, mac, ipaddress, default_router)
            logger.debug("Creating DHCP cfg for Cobbler system (location: " + systemobject.loc + ") with: " + 
                         systemobject.hostname + " " + systemobject.mac + " " + systemobject.router )
            systemobject.create_cfg_file()
            orig = sys.stdout  # initial stdout
            sys.stdout = open(LOG_FILE, "a")  # want to read cfg file into log 
            logger.debug("Checking the cfg file:")
            systemobject.read_cfg_file()
            sys.stdout.close()
            sys.stdout = orig  # restore initial stdout
    except:
        logger.debug("ERROR: Cannot create DHCP cfg for Cobbler system " + system)
        sys.exit("ERROR: Cannot create DHCP cfg for Cobbler system " + system)

def create_s11_cfg_file():
    """
    Note: dash (-) & dot (.) can't be used in object name,
          hence we create first systemobject
    """
    systemobject = system.replace("-", "_").replace(".", "_")
    logger.debug("System's object/ID: " + systemobject)
    try:
        systemobject =  dhcp_cfg.S11_SYSTEM(LOC, systemfqdn, mac, ipaddress)
        logger.debug("Creating DHCP cfg for Solaris11 system (location: " + systemobject.loc + ") with: " + 
                     systemobject.hostname + " " + systemobject.mac )
        systemobject.create_cfg_file()
        orig = sys.stdout  # initial stdout
        sys.stdout = open(LOG_FILE, "a")  # want to read cfg file into log
        logger.debug("Checking the cfg file:")
        systemobject.read_cfg_file()
        sys.stdout.close()
        sys.stdout = orig  # restore initial stdout
    except:
        logger.debug("ERROR: Cannot create DHCP cfg for Solaris 11 system " + system)
        sys.exit("ERROR: Cannot create DHCP cfg for Solaris 11 system " + system)

def create_ak_cfg_file():
    """
    Note: dash (-) & dot (.) can't be used in object name,
          hence we create first systemobject
    """
    systemobject = system.replace("-", "_").replace(".", "_")
    logger.debug("System's object/ID: " + systemobject)
    try:
        systemobject =  dhcp_cfg.AK_SYSTEM(LOC, systemfqdn, mac, ipaddress)
        logger.debug("Creating DHCP cfg for AK system (location: " + systemobject.loc + ") with: " +
                     systemobject.hostname + " " + systemobject.mac )
        systemobject.create_cfg_file()
        orig = sys.stdout  # initial stdout
        sys.stdout = open(LOG_FILE, "a")  # want to read cfg file into log
        logger.debug("Checking the cfg file:")
        systemobject.read_cfg_file()
        sys.stdout.close()
        sys.stdout = orig  # restore initial stdout
    except:
        logger.debug("ERROR: Cannot create DHCP cfg for AK system " + system)
        sys.exit("ERROR: Cannot create DHCP cfg for AK system " + system)

def create_s10_cfg_file():
    """
    Note: dash (-) & dot (.) can't be used in object name,
          hence we create first systemobject
    """
    systemobject = system.replace("-", "_").replace(".", "_")
    logger.debug("System's object/ID: " + systemobject)
    try:
        systemobject =  dhcp_cfg.S10_SYSTEM_X86(LOC, systemfqdn, mac, ipaddress)
        logger.debug("Creating DHCP cfg for Solaris10 x86 system (location: " + systemobject.loc + ") with: " +
                     systemobject.hostname + " " + systemobject.mac )
        systemobject.create_cfg_file()
        orig = sys.stdout  # initial stdout
        sys.stdout = open(LOG_FILE, "a")  # want to read cfg file into log
        logger.debug("Checking the cfg file:")
        systemobject.read_cfg_file()
        sys.stdout.close()
        sys.stdout = orig  # restore initial stdout
    except:
        logger.debug("ERROR: Cannot create DHCP cfg for Solaris 10 x86 system " + system)
        sys.exit("ERROR: Cannot create DHCP cfg for Solaris 10 x86 system " + system)

def compile_client_list():
    """
    Compile list of clients for clients.include file.
    Need to import os module again or get error:
    AttributeError: '_MutuallyExclusiveGroup' object has no attribute 'path'
    Need to troubleshoot more!?
    """
    import os
    CLIENTSDIR = "/etc/dhcp/clients/"
    if not os.path.exists(CLIENTSDIR):
        logger.debug("ERROR: " + CLIENTSDIR + " does not exist.")
        sys.exit("ERROR: " + CLIENTSDIR + " does not exist.")
    f = open("/etc/dhcp/clients.include", "w+")
    try:
        for root, dirs, files in os.walk(CLIENTSDIR):
            for clientname in files:
                f.write("include \"" + CLIENTSDIR + clientname + "\" ;\n")
        logger.debug("OK: Compiled new /etc/dhcp/clients.include")
    except:
        logger.debug("ERROR: cannot compile /etc/dhcp/clients.include")
        sys.exit("ERROR: cannot compile /etc/dhcp/clients.include")
    f.close()

def dhcp_cfg_check():
    """
    Check DHCP cfg syntax
    """
    return True if subprocess.call(['service', 'dhcpd', 'configtest']) == 0 else False

def dhcp_restart():
    """
    Restart DHCP service
    """
    return True if subprocess.call(['service', 'dhcpd', 'restart']) == 0 else False

 
# ---- MAIN -----
if __name__ == '__main__':

    if linuxinstall:
        print ("Install type: Linux")
        logger.debug("Install type: Linux")
        find_ip()
        subnet_check(ipaddress)
        create_cobbler_cfg_file()
        compile_client_list()
        if not dhcp_cfg_check():
            logger.debug("ERROR: DHCP config check fails")
            sys.exit("ERROR: DHCP config check fails")
        else:
            logger.debug("OK: DHCP config looks good")
        
        if not dhcp_restart():
            logger.debug("ERROR: DHCP service restart fails")
            sys.exit("ERROR: DHCP service restart fails")
        else:
            logger.debug("OK: DHCP service has been restarted")

    elif s11install:
        print ("Install type: Solaris 11")
        logger.debug("Install type: Solaris 11")
        find_ip()
        subnet_check(ipaddress)
        create_s11_cfg_file()
        compile_client_list()
        if not dhcp_cfg_check():
            logger.debug("ERROR: DHCP config check fails")
            sys.exit("ERROR: DHCP config check fails")
        else:
            logger.debug("OK: DHCP config looks good")

        if not dhcp_restart():
            logger.debug("ERROR: DHCP service restart fails")
            sys.exit("ERROR: DHCP service restart fails")
        else:
            logger.debug("OK: DHCP service has been restarted")

    elif akinstall:
        print ("Install type: AK")
        logger.debug("Install type: AK")
        find_ip()
        subnet_check(ipaddress)
        create_ak_cfg_file()
        compile_client_list()
        if not dhcp_cfg_check():
            logger.debug("ERROR: DHCP config check fails")
            sys.exit("ERROR: DHCP config check fails")
        else:
            logger.debug("OK: DHCP config looks good")

        if not dhcp_restart():
            logger.debug("ERROR: DHCP service restart fails")
            sys.exit("ERROR: DHCP service restart fails")
        else:
            logger.debug("OK: DHCP service has been restarted")

    elif s10install:
        print ("Install type: Solaris 10 x86")
        logger.debug("Install type: Solaris 10 x86")
        find_ip()
        subnet_check(ipaddress)
        create_s10_cfg_file()    # arch is checked inside function
        compile_client_list()
        if not dhcp_cfg_check():
            logger.debug("ERROR: DHCP config check fails")
            sys.exit("ERROR: DHCP config check fails")
        else:
            logger.debug("OK: DHCP config looks good")

        if not dhcp_restart():
            logger.debug("ERROR: DHCP service restart fails")
            sys.exit("ERROR: DHCP service restart fails")
        else:
            logger.debug("OK: DHCP service has been restarted")
 
    logger.debug("FINISH AT : " + strftime("%a, %d %b %Y %H:%M:%S", gmtime()))

Usage

[zdudic@dhcp-server ~]which ca-dhcp-reserve.py
/usr/bin/ca-dhcp-reserve.py

[zdudic@dhcp-server ~]sudo !!
sudo ca-dhcp-reserve.py
usage: ca-dhcp-reserve.py [-h] (-l | -i | -j | -z) -s SYSTEM -m MAC
                          [-b BOOTFILE]
ca-dhcp-reserve.py: error: argument -s/--system is required

[zdudic@ca-dhcp-sca ~]ca-dhcp-reserve.py -h
zdudic, please run this via sudo (otherwise you won't have permissions to complete reservation)

[zdudic@dhcp-server ~]sudo !!
sudo ca-dhcp-reserve.py -h
usage: ca-dhcp-reserve.py [-h] (-l | -i | -j | -z) -s SYSTEM -m MAC
                          [-b BOOTFILE]

Add DHCP cfg file for a system (location: sca )

optional arguments:
  -h, --help            show this help message and exit
  -l, --linux           Linux install via Cobbler
  -i, --solaris11       Solaris 11 install
  -j, --solaris10       Solaris 10 x86 install (SPARC is not supported)
  -z, --ak              AK install
  -s SYSTEM, --system SYSTEM
                        System's FQDN
  -m MAC, --mac MAC     System's MAC ( : as delimiter)
  -b BOOTFILE, --bootfile BOOTFILE
                        Custom boot file, only linux install (it must be in
                        :/tftpboot)

Brought to you by LabOps
Back to the main page