diff options
author | Michael DeHaan <mdehaan@redhat.com> | 2008-05-02 16:05:32 -0400 |
---|---|---|
committer | Michael DeHaan <mdehaan@redhat.com> | 2008-05-02 16:05:32 -0400 |
commit | a6fd395b51a624e4aa7d09b4960382784cefa8e8 (patch) | |
tree | 6fdab90d58f4d673f1e5e58201a032cd9eb7386b /cobbler | |
parent | e4fce2b7321c880f8c1f1adbdf137fc4d66563de (diff) | |
download | third_party-cobbler-a6fd395b51a624e4aa7d09b4960382784cefa8e8.tar.gz third_party-cobbler-a6fd395b51a624e4aa7d09b4960382784cefa8e8.tar.xz third_party-cobbler-a6fd395b51a624e4aa7d09b4960382784cefa8e8.zip |
Working on moving DNS/DHCP management to cobbler/modules (uses modules.conf)
In progress.
Diffstat (limited to 'cobbler')
-rw-r--r-- | cobbler/action_check.py | 8 | ||||
-rw-r--r-- | cobbler/action_litesync.py | 24 | ||||
-rw-r--r-- | cobbler/action_sync.py | 18 | ||||
-rw-r--r-- | cobbler/api.py | 17 | ||||
-rw-r--r-- | cobbler/dhcpgen.py | 282 | ||||
-rw-r--r-- | cobbler/manage_ctrl.py | 76 | ||||
-rw-r--r-- | cobbler/modules/manage_dnsmasq.py | 191 | ||||
-rw-r--r-- | cobbler/modules/manage_isc_and_bind.py | 425 |
8 files changed, 731 insertions, 310 deletions
diff --git a/cobbler/action_check.py b/cobbler/action_check.py index e91396f..588a65a 100644 --- a/cobbler/action_check.py +++ b/cobbler/action_check.py @@ -37,8 +37,8 @@ class BootCheck: status = [] self.check_name(status) if self.settings.manage_dhcp: - mode = self.settings.manage_dhcp_mode.lower() - if mode == "isc": + mode = self.config.api.get_sync().manager.what() + if mode == "isc_and_bind": self.check_dhcpd_bin(status) self.check_dhcpd_conf(status) self.check_service(status,"dhcpd") @@ -46,7 +46,9 @@ class BootCheck: self.check_dnsmasq_bin(status) self.check_service(status,"dnsmasq") else: - status.append(_("manage_dhcp_mode in /var/lib/cobbler/settings should be 'isc' or 'dnsmasq'")) + status.append(_("configured management mode in modules.conf is unknown")) + # FIXME: add in checks for bind config + self.check_service(status, "cobblerd") self.check_bootloaders(status) diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py index c2029d4..ba0a256 100644 --- a/cobbler/action_litesync.py +++ b/cobbler/action_litesync.py @@ -49,7 +49,7 @@ class BootLiteSync: self.systems = config.systems() self.settings = config.settings() self.repos = config.repos() - self.sync = action_sync.BootSync(self.config) + self.sync = config.api.get_sync() def add_single_distro(self, name): # get the distro record @@ -105,12 +105,22 @@ class BootLiteSync: if system is None: raise CX(_("error in system lookup for %s") % name) # rebuild system_list file in webdir - self.sync.dhcpgen.regen_ethers() # /etc/ethers, for dnsmasq & rarpd - self.sync.dhcpgen.regen_hosts() # /var/lib/cobbler/cobbler_hosts, pretty much for dnsmasq + self.sync.manager.regen_ethers() + self.sync.manager.regen_hosts() # write the PXE files for the system self.sync.pxegen.write_all_system_files(system) # per system kickstarts self.sync.yumgen.retemplate_yum_repos(system,False) + if self.settings.manage_dhcp: + if self.settings.omapi_enabled: + for (name,interface) in system.interfaces.iteritems(): + self.sync.manager.write_dhcp_lease( + self.settings.omapi_port, + interface["hostname"], + interface["mac-address"], + interface["ip-address"] + ) + def remove_single_system(self, name): bootloc = utils.tftpboot_location() @@ -122,6 +132,14 @@ class BootLiteSync: filename = utils.get_config_filename(system_record,interface=name) utils.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename)) + if self.settings.manage_dhcp: + if self.settings.omapi_enabled: + for (name,interface) in system_record.interfaces.iteritems(): + self.sync.manager.remove_dhcp_lease( + self.settings.omapi_port, + interface["hostname"] + ) + # unneeded #if not system_record.is_pxe_supported(): # # no need to go any further with PXE cleanup diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index 53ef3a7..fbc9402 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -28,8 +28,7 @@ import utils from cexceptions import * import templar import pxegen -import dhcpgen -import dnsgen +import manage_ctrl import yumgen import item_distro @@ -47,7 +46,7 @@ class BootSync: Handles conversion of internal state to the tftpboot tree layout """ - def __init__(self,config,verbose=False,dhcp=None,dns=None): + def __init__(self,config,verbose=False,manage=None): """ Constructor """ @@ -61,7 +60,7 @@ class BootSync: self.repos = config.repos() self.templar = templar.Templar(config) self.pxegen = pxegen.PXEGen(config) - self.dhcpgen = dhcpgen.DHCPGen(config) + self.manager = manage self.yumgen = yumgen.YumGen(config) self.bootloc = utils.tftpboot_location() @@ -84,8 +83,6 @@ class BootSync: self.settings = self.config.settings() self.repos = self.config.repos() self.pxegen = pxegen.PXEGen(self.config) - self.dhcpgen = dhcpgen.DHCPGen(self.config) - self.dnsgen = dnsgen.DNSGen(self.config) self.yumgen = yumgen.YumGen(self.config) # execute the core of the sync operation @@ -96,12 +93,11 @@ class BootSync: self.pxegen.write_all_system_files(x) self.yumgen.retemplate_all_yum_repos() if self.settings.manage_dhcp: - # these functions DRT for ISC or dnsmasq - self.dhcpgen.write_dhcp_file() - self.dhcpgen.regen_ethers() - self.dhcpgen.regen_hosts() + self.manager.write_dhcp_file() + self.manager.regen_ethers() + self.manager.regen_hosts() if self.settings.manage_dns: - self.dnsgen.write_bind_files() + self.manager.write_dns_files() self.pxegen.make_pxe_menu() # run post-triggers diff --git a/cobbler/api.py b/cobbler/api.py index 29a854d..1f5a246 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -81,16 +81,6 @@ class BootAPI: "module", "authz_allowall" ) - self.dhcp = self.get_module_from_file( - "dhcp_management", - "module", - "dhcp_isc" - ) - self.dns = self.get_module_from_file( - "dns_management", - "module", - "dns_bind" - ) self.kickgen = kickgen.KickGen(self._config) self.logger.debug("API handle initialized") @@ -346,7 +336,12 @@ class BootAPI: return sync.run() def get_sync(self): - return action_sync.BootSync(self._config,dhcp=self.dhcp,dns=self.dns) + self.manage = self.get_module_from_file( + "management", + "module", + "manage_isc_and_bind" + ).get_manager(self._config) + return action_sync.BootSync(self._config,manage=self.manage) def reposync(self, name=None): """ diff --git a/cobbler/dhcpgen.py b/cobbler/dhcpgen.py deleted file mode 100644 index 5dd981c..0000000 --- a/cobbler/dhcpgen.py +++ /dev/null @@ -1,282 +0,0 @@ -""" -Builds out DHCP info -This is the code behind 'cobbler sync'. - -Copyright 2006-2008, Red Hat, Inc -Michael DeHaan <mdehaan@redhat.com> - -This software may be freely redistributed under the terms of the GNU -general public license. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -""" - -import os -import os.path -import shutil -import time -import sub_process -import sys -import glob -import traceback -import errno -import popen2 -from shlex import shlex - - -import utils -from cexceptions import * -import templar - -import item_distro -import item_profile -import item_repo -import item_system - -from utils import _ - -class DHCPGen: - """ - Handles conversion of internal state to the tftpboot tree layout - """ - - def __init__(self,config,verbose=False): - """ - Constructor - """ - self.verbose = verbose - self.config = config - self.api = config.api - self.distros = config.distros() - self.profiles = config.profiles() - self.systems = config.systems() - self.settings = config.settings() - self.repos = config.repos() - self.templar = templar.Templar(config) - - def writeDHCPLease(self,port,host,ip,mac): - """writeDHCPLease(port,host,ip,mac) - Use DHCP's API to create a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """ - #Code from http://svn.osgdc.org/browse/kusu/kusu/trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025 - # FIXME: should use subprocess - try: - fromchild, tochild = popen2.popen2("/usr/bin/omshell") - tochild.write("port %s\n" % port) - tochild.flush() - tochild.write("connect\n") - tochild.flush() - tochild.write("new host\n") - tochild.flush() - tochild.write('set name = \"%s\"\n' % host) - tochild.flush() - tochild.write("set ip-address = %s\n" % ip) - tochild.flush() - tochild.write("set hardware-address = %s\n" % mac) - tochild.flush() - tochild.write("set hardware-type = 1\n") - tochild.flush() - tochild.write("create\n") - tochild.flush() - tochild.close() - fromchild.close() - except IOError: - # FIXME: just catch 32 (broken pipe) and show a warning - pass - - def removeDHCPLease(self,port,host): - """removeDHCPLease(port,host) - Use DHCP's API to delete a DHCP entry in the /var/lib/dhcpd/dhcpd.leases file """ - fromchild, tochild = popen2.popen2("/usr/bin/omshell") - try: - tochild.write("port %s\n" % port) - tochild.flush() - tochild.write("connect\n") - tochild.flush() - tochild.write("new host\n") - tochild.flush() - tochild.write('set name = \"%s\"\n' % host) - tochild.flush() - tochild.write("open\n") # opens register with host information - tochild.flush() - tochild.write("remove\n") - tochild.flush() - tochild.close() - fromchild.close() - except IOError: - # FIXME: convert this to subprocess. - # FIXME: catch specific errors only (32/broken pipe) - pass - - - def write_dhcp_file(self): - """ - DHCP files are written when manage_dhcp is set in - /var/lib/cobbler/settings. - """ - - settings_file = self.settings.dhcpd_conf - template_file = "/etc/cobbler/dhcp.template" - mode = self.settings.manage_dhcp_mode.lower() - if mode == "dnsmasq": - settings_file = self.settings.dnsmasq_conf - template_file = "/etc/cobbler/dnsmasq.template" - - try: - f2 = open(template_file,"r") - except: - raise CX(_("error writing template to file: %s") % template_file) - template_data = "" - template_data = f2.read() - f2.close() - - # build each per-system definition - # as configured, this only works for ISC, patches accepted - # from those that care about Itanium. elilo seems to be unmaintained - # so additional maintaince in other areas may be required to keep - # this working. - - elilo = os.path.basename(self.settings.bootloaders["ia64"]) - - system_definitions = {} - counter = 0 - - - # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in - # case to avoid conflicts with the hosts we're defining and to clean - # possible removed hosts (only if using OMAPI) - if self.settings.omapi_enabled and self.settings.omapi_port: - if os.path.exists("/var/lib/dhcpd/dhcpd.leases"): - file = open('/var/lib/dhcpd/dhcpd.leases') - item = shlex(file) - while 1: - elem = item.get_token() - if not elem: - break - if elem == 'host': - hostremove = item.get_token() - self.removeDHCPLease(self.settings.omapi_port,hostremove) - - # we used to just loop through each system, but now we must loop - # through each network interface of each system. - - for system in self.systems: - profile = system.get_conceptual_parent() - distro = profile.get_conceptual_parent() - for (name, interface) in system.interfaces.iteritems(): - - mac = interface["mac_address"] - ip = interface["ip_address"] - host = interface["hostname"] - - if mac is None or mac == "": - # can't write a DHCP entry for this system - continue - - counter = counter + 1 - systxt = "" - - if mode == "isc": - - # the label the entry after the hostname if possible - if host is not None and host != "": - systxt = "\nhost %s {\n" % host - if self.settings.isc_set_host_name: - systxt = systxt + " option host-name = \"%s\";\n" % host - else: - systxt = "\nhost generic%d {\n" % counter - - if distro.arch == "ia64": - # can't use pxelinux.0 anymore - systxt = systxt + " filename \"/%s\";\n" % elilo - systxt = systxt + " hardware ethernet %s;\n" % mac - if ip is not None and ip != "": - systxt = systxt + " fixed-address %s;\n" % ip - systxt = systxt + "}\n" - - # If we have all values defined and we're using omapi, - # we will just create entries dinamically into DHCPD - # without requiring a restart (but file will be written - # as usual for having it working after restart) - - if ip is not None and ip != "": - if mac is not None and mac != "": - if host is not None and host != "": - if self.settings.omapi_enabled and self.settings.omapi_port: - self.removeDHCPLease(self.settings.omapi_port,host) - self.writeDHCPLease(self.settings.omapi_port,host,ip,mac) - - - else: - # dnsmasq. don't have to write IP and other info here, but we do tag - # each MAC based on the arch of it's distro, if it needs something other - # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq - # reload (full "cobbler sync") would be required after adding the system - # to cobbler, just to tag this relationship. - - if ip is not None and ip != "": - if distro.arch.lower() == "ia64": - systxt = "dhcp-host=net:ia64," + ip + "\n" - # support for other arches needs modifications here - else: - systxt = "" - - dhcp_tag = interface["dhcp_tag"] - if dhcp_tag == "": - dhcp_tag = "default" - - if not system_definitions.has_key(dhcp_tag): - system_definitions[dhcp_tag] = "" - system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt - - # we are now done with the looping through each interface of each system - - metadata = { - "omapi_enabled" : self.settings.omapi_enabled, - "omapi_port" : self.settings.omapi_port, - "insert_cobbler_system_definitions" : system_definitions.get("default",""), - "date" : time.asctime(time.gmtime()), - "cobbler_server" : self.settings.server, - "next_server" : self.settings.next_server, - "elilo" : elilo - } - - # now add in other DHCP expansions that are not tagged with "default" - for x in system_definitions.keys(): - if x == "default": - continue - metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x] - - self.templar.render(template_data, metadata, settings_file, None) - - def regen_ethers(self): - # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date - # every time we add a system. - # read 'man ethers' for format info - fh = open("/etc/ethers","w+") - for sys in self.systems: - for (name, interface) in sys.interfaces.iteritems(): - mac = interface["mac_address"] - ip = interface["ip_address"] - if mac is None or mac == "": - # can't write this w/o a MAC address - continue - if ip is not None and ip != "": - fh.write(mac.upper() + "\t" + ip + "\n") - fh.close() - - def regen_hosts(self): - # dnsmasq knows how to read this database for host info - # (other things may also make use of this later) - fh = open("/var/lib/cobbler/cobbler_hosts","w+") - for sys in self.systems: - for (name, interface) in sys.interfaces.iteritems(): - mac = interface["mac_address"] - host = interface["hostname"] - ip = interface["ip_address"] - if mac is None or mac == "": - continue - if host is not None and host != "" and ip is not None and ip != "": - fh.write(ip + "\t" + host + "\n") - fh.close() diff --git a/cobbler/manage_ctrl.py b/cobbler/manage_ctrl.py new file mode 100644 index 0000000..a01910a --- /dev/null +++ b/cobbler/manage_ctrl.py @@ -0,0 +1,76 @@ +""" +Builds out DHCP info +This is the code behind 'cobbler sync'. + +Copyright 2006-2008, Red Hat, Inc +Michael DeHaan <mdehaan@redhat.com> + +This software may be freely redistributed under the terms of the GNU +general public license. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +""" + +import os +import os.path +import shutil +import time +import sub_process +import sys +import glob +import traceback +import errno +import popen2 +from shlex import shlex + + +import utils +from cexceptions import * +import templar + +import item_distro +import item_profile +import item_repo +import item_system + +from utils import _ + +class ManageCtrl: + """ + Handles conversion of internal state to the tftpboot tree layout + """ + + def __init__(self,config,verbose=False,dns=None,dhcp=None): + """ + Constructor + """ + self.verbose = verbose + self.config = config + self.api = config.api + self.distros = config.distros() + self.profiles = config.profiles() + self.systems = config.systems() + self.settings = config.settings() + self.repos = config.repos() + self.templar = templar.Templar(config) + self.dns = dns + + def write_dhcp_lease(self,port,host,ip,mac): + return dhcp.write_dhcp_lease(port,host,ip,mac) + + def remove_dhcp_lease(self,port,host): + return dhcp.remove_dhcp_lease(port,host) + + def write_dhcp_file(self): + return dhcp.write_dhcp_file() + + def regen_ethers(self): + return dhcp.regen_ethers() + + def regen_hosts(self): + return dns.regen_hosts() + + def write_dns_files(self): + return dns.write_bind_files() diff --git a/cobbler/modules/manage_dnsmasq.py b/cobbler/modules/manage_dnsmasq.py new file mode 100644 index 0000000..d37a2d4 --- /dev/null +++ b/cobbler/modules/manage_dnsmasq.py @@ -0,0 +1,191 @@ + +""" +This is some of the code behind 'cobbler sync'. + +Copyright 2006-2008, Red Hat, Inc +Michael DeHaan <mdehaan@redhat.com> +John Eckersberg <jeckersb@redhat.com> + +This software may be freely redistributed under the terms of the GNU +general public license. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +""" + +import os +import os.path +import shutil +import time +import sub_process +import sys +import glob +import traceback +import errno +import popen2 +from shlex import shlex +import utils +from cexceptions import * +import templar +import item_distro +import item_profile +import item_repo +import item_system +from utils import _ + +def register(): + return "manage" + +class DnsmasqManager: + """ + Handles conversion of internal state to the tftpboot tree layout + """ + + def __init__(self,config,verbose=False,dhcp=None): + """ + Constructor + """ + self.verbose = verbose + self.config = config + self.api = config.api + self.distros = config.distros() + self.profiles = config.profiles() + self.systems = config.systems() + self.settings = config.settings() + self.repos = config.repos() + self.templar = templar.Templar(config) + self.dns = dns + + def what(self): + return "dnsmasq" + + def write_dhcp_lease(self,port,host,ip,mac): + pass + + def remove_dhcp_lease(self,port,host): + pass + + + def write_dhcp_file(self): + """ + DHCP files are written when manage_dhcp is set in + /var/lib/cobbler/settings. + """ + + settings_file = self.settings.dnsmasq_conf + template_file = "/etc/cobbler/dnsmasq.template" + + try: + f2 = open(template_file,"r") + except: + raise CX(_("error writing template to file: %s") % template_file) + template_data = "" + template_data = f2.read() + f2.close() + + # build each per-system definition + # as configured, this only works for ISC, patches accepted + # from those that care about Itanium. elilo seems to be unmaintained + # so additional maintaince in other areas may be required to keep + # this working. + + elilo = os.path.basename(self.settings.bootloaders["ia64"]) + + system_definitions = {} + counter = 0 + + # we used to just loop through each system, but now we must loop + # through each network interface of each system. + + for system in self.systems: + profile = system.get_conceptual_parent() + distro = profile.get_conceptual_parent() + for (name, interface) in system.interfaces.iteritems(): + + mac = interface["mac_address"] + ip = interface["ip_address"] + host = interface["hostname"] + + if mac is None or mac == "": + # can't write a DHCP entry for this system + continue + + counter = counter + 1 + systxt = "" + + # dnsmasq. don't have to write IP and other info here, but we do tag + # each MAC based on the arch of it's distro, if it needs something other + # than pxelinux.0 -- for these arches, and these arches only, a dnsmasq + # reload (full "cobbler sync") would be required after adding the system + # to cobbler, just to tag this relationship. + + if ip is not None and ip != "": + if distro.arch.lower() == "ia64": + systxt = "dhcp-host=net:ia64," + ip + "\n" + # support for other arches needs modifications here + else: + systxt = "" + + dhcp_tag = interface["dhcp_tag"] + if dhcp_tag == "": + dhcp_tag = "default" + + if not system_definitions.has_key(dhcp_tag): + system_definitions[dhcp_tag] = "" + system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt + + # we are now done with the looping through each interface of each system + + metadata = { + "omapi_enabled" : self.settings.omapi_enabled, + "omapi_port" : self.settings.omapi_port, + "insert_cobbler_system_definitions" : system_definitions.get("default",""), + "date" : time.asctime(time.gmtime()), + "cobbler_server" : self.settings.server, + "next_server" : self.settings.next_server, + "elilo" : elilo + } + + # now add in other DHCP expansions that are not tagged with "default" + for x in system_definitions.keys(): + if x == "default": + continue + metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x] + + self.templar.render(template_data, metadata, settings_file, None) + + def regen_ethers(self): + # dnsmasq knows how to read this database of MACs -> IPs, so we'll keep it up to date + # every time we add a system. + # read 'man ethers' for format info + fh = open("/etc/ethers","w+") + for sys in self.systems: + for (name, interface) in sys.interfaces.iteritems(): + mac = interface["mac_address"] + ip = interface["ip_address"] + if mac is None or mac == "": + # can't write this w/o a MAC address + continue + if ip is not None and ip != "": + fh.write(mac.upper() + "\t" + ip + "\n") + fh.close() + + def regen_hosts(self): + # dnsmasq knows how to read this database for host info + # (other things may also make use of this later) + fh = open("/var/lib/cobbler/cobbler_hosts","w+") + for sys in self.systems: + for (name, interface) in sys.interfaces.iteritems(): + mac = interface["mac_address"] + host = interface["hostname"] + ip = interface["ip_address"] + if mac is None or mac == "": + continue + if host is not None and host != "" and ip is not None and ip != "": + fh.write(ip + "\t" + host + "\n") + fh.close() + +def get_manager(config): + return DnsmasqManager(config) + diff --git a/cobbler/modules/manage_isc_and_bind.py b/cobbler/modules/manage_isc_and_bind.py new file mode 100644 index 0000000..bc3a338 --- /dev/null +++ b/cobbler/modules/manage_isc_and_bind.py @@ -0,0 +1,425 @@ +""" +This is some of the code behind 'cobbler sync'. + +Copyright 2006-2008, Red Hat, Inc +Michael DeHaan <mdehaan@redhat.com> +John Eckersberg <jeckersb@redhat.com> + +This software may be freely redistributed under the terms of the GNU +general public license. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +""" + +import os +import os.path +import shutil +import time +import sub_process +import sys +import glob +import traceback +import errno +import popen2 +from shlex import shlex + + +import utils +from cexceptions import * +import templar + +import item_distro +import item_profile +import item_repo +import item_system + +from utils import _ + + +def register(): + """ + The mandatory cobbler module registration hook. + """ + return "manage" + + +class IscAndBindManager: + + def what(self): + return "isc_and_bind" + + def __init__(self,config,verbose=False): + """ + Constructor + """ + self.verbose = verbose + self.config = config + self.api = config.api + self.distros = config.distros() + self.profiles = config.profiles() + self.systems = config.systems() + self.settings = config.settings() + self.repos = config.repos() + self.templar = templar.Templar(config) + + def write_dhcp_lease(self,port,host,ip,mac): + """ + Use DHCP's API to create a DHCP entry in the + /var/lib/dhcpd/dhcpd.leases file + #Code from http://svn.osgdc.org/browse/kusu/kusu + # /trunk/src/kits/base/packages/kusu-base-installer/lib/kusu/nodefun.py?r=3025 + # FIXME: should use subprocess + """ + try: + fromchild, tochild = popen2.popen2("/usr/bin/omshell") + tochild.write("port %s\n" % port) + tochild.flush() + tochild.write("connect\n") + tochild.flush() + tochild.write("new host\n") + tochild.flush() + tochild.write('set name = \"%s\"\n' % host) + tochild.flush() + tochild.write("set ip-address = %s\n" % ip) + tochild.flush() + tochild.write("set hardware-address = %s\n" % mac) + tochild.flush() + tochild.write("set hardware-type = 1\n") + tochild.flush() + tochild.write("create\n") + tochild.flush() + tochild.close() + fromchild.close() + except IOError: + # FIXME: just catch 32 (broken pipe) and show a warning + pass + + def remove_dhcp_lease(self,port,host): + """ + removeDHCPLease(port,host) + Use DHCP's API to delete a DHCP entry in + the /var/lib/dhcpd/dhcpd.leases file + """ + fromchild, tochild = popen2.popen2("/usr/bin/omshell") + try: + tochild.write("port %s\n" % port) + tochild.flush() + tochild.write("connect\n") + tochild.flush() + tochild.write("new host\n") + tochild.flush() + tochild.write('set name = \"%s\"\n' % host) + tochild.flush() + tochild.write("open\n") # opens register with host information + tochild.flush() + tochild.write("remove\n") + tochild.flush() + tochild.close() + fromchild.close() + except IOError: + # FIXME: convert this to subprocess. + # FIXME: catch specific errors only (32/broken pipe) + pass + + def write_dhcp_file(self): + """ + DHCP files are written when manage_dhcp is set in + /var/lib/cobbler/settings. + """ + + settings_file = self.settings.dhcpd_conf + template_file = "/etc/cobbler/dhcp.template" + mode = self.settings.manage_dhcp_mode.lower() + + try: + f2 = open(template_file,"r") + except: + raise CX(_("error writing template to file: %s") % template_file) + template_data = "" + template_data = f2.read() + f2.close() + + # build each per-system definition + # as configured, this only works for ISC, patches accepted + # from those that care about Itanium. elilo seems to be unmaintained + # so additional maintaince in other areas may be required to keep + # this working. + + elilo = os.path.basename(self.settings.bootloaders["ia64"]) + + system_definitions = {} + counter = 0 + + + # Clean system definitions in /var/lib/dhcpd/dhcpd.leases just in + # case to avoid conflicts with the hosts we're defining and to clean + # possible removed hosts (only if using OMAPI) + if self.settings.omapi_enabled and self.settings.omapi_port: + if os.path.exists("/var/lib/dhcpd/dhcpd.leases"): + file = open('/var/lib/dhcpd/dhcpd.leases') + item = shlex(file) + while 1: + elem = item.get_token() + if not elem: + break + if elem == 'host': + hostremove = item.get_token() + self.removeDHCPLease(self.settings.omapi_port,hostremove) + + # we used to just loop through each system, but now we must loop + # through each network interface of each system. + + for system in self.systems: + profile = system.get_conceptual_parent() + distro = profile.get_conceptual_parent() + for (name, interface) in system.interfaces.iteritems(): + + mac = interface["mac_address"] + ip = interface["ip_address"] + host = interface["hostname"] + + if mac is None or mac == "": + # can't write a DHCP entry for this system + continue + + counter = counter + 1 + systxt = "" + + + # the label the entry after the hostname if possible + if host is not None and host != "": + systxt = "\nhost %s {\n" % host + if self.settings.isc_set_host_name: + systxt = systxt + " option host-name = \"%s\";\n" % host + else: + systxt = "\nhost generic%d {\n" % counter + + if distro.arch == "ia64": + # can't use pxelinux.0 anymore + systxt = systxt + " filename \"/%s\";\n" % elilo + systxt = systxt + " hardware ethernet %s;\n" % mac + if ip is not None and ip != "": + systxt = systxt + " fixed-address %s;\n" % ip + systxt = systxt + "}\n" + + # If we have all values defined and we're using omapi, + # we will just create entries dinamically into DHCPD + # without requiring a restart (but file will be written + # as usual for having it working after restart) + + if ip is not None and ip != "": + if mac is not None and mac != "": + if host is not None and host != "": + if self.settings.omapi_enabled and self.settings.omapi_port: + self.removeDHCPLease(self.settings.omapi_port,host) + self.writeDHCPLease(self.settings.omapi_port,host,ip,mac) + + dhcp_tag = interface["dhcp_tag"] + if dhcp_tag == "": + dhcp_tag = "default" + + if not system_definitions.has_key(dhcp_tag): + system_definitions[dhcp_tag] = "" + system_definitions[dhcp_tag] = system_definitions[dhcp_tag] + systxt + + # we are now done with the looping through each interface of each system + + metadata = { + "omapi_enabled" : self.settings.omapi_enabled, + "omapi_port" : self.settings.omapi_port, + "insert_cobbler_system_definitions" : system_definitions.get("default",""), + "date" : time.asctime(time.gmtime()), + "cobbler_server" : self.settings.server, + "next_server" : self.settings.next_server, + "elilo" : elilo + } + + # now add in other DHCP expansions that are not tagged with "default" + for x in system_definitions.keys(): + if x == "default": + continue + metadata["insert_cobbler_system_definitions_%s" % x] = system_definitions[x] + + self.templar.render(template_data, metadata, settings_file, None) + + def regen_ethers(self): + pass # ISC/BIND do not use this + + + def regen_hosts(self): + pass # ISC/BIND do not use this + + + def __forward_zones(self): + """ + Returns ALL forward zones for all systems + """ + zones = {} + for sys in self.systems: + for (name, interface) in sys.interfaces.iteritems(): + host = interface["hostname"] + ip = interface["ip_address"] + if not host or not ip: + # gotsta have some hostname and ip or else! + continue + tokens = host.split('.') + zone = '.'.join(tokens[1:]) + if zones.has_key(zone): + zones[zone].append((host.split('.')[0], ip)) + else: + zones[zone] = [(host.split('.')[0], ip)] + return zones + + def __reverse_zones(self): + """ + Returns ALL reverse zones for all systems + """ + zones = {} + for sys in self.systems: + for (name, interface) in sys.interfaces.iteritems(): + host = interface["hostname"] + ip = interface["ip_address"] + if not host or not ip: + # gotsta have some hostname and ip or else! + continue + tokens = ip.split('.') + zone = '.'.join(tokens[0:3]) + if zones.has_key(zone): + zones[zone].append((tokens[3], host + '.')) + else: + zones[zone] = [(tokens[3], host + '.')] + return zones + + def __config_forward_zones(self): + """ + Returns only the forward zones which have systems and are defined + in the option manage_forward_zones + + Alternatively if manage_forward_zones is empty, return all systems + """ + all = self.__forward_zones() + want = self.settings.manage_forward_zones + if want == []: return all + ret = {} + for zone in all.keys(): + if zone in want: + ret[zone] = all[zone] + return ret + + def __config_reverse_zones(self): + """ + Returns only the reverse zones which have systems and are defined + in the option manage_reverse_zones + + Alternatively if manage_reverse_zones is empty, return all systems + """ + all = self.__reverse_zones() + want = self.settings.manage_reverse_zones + if want == []: return all + ret = {} + for zone in all.keys(): + if zone in want: + ret[zone] = all[zone] + return ret + + def __write_named_conf(self): + """ + Write out the named.conf main config file from the template. + """ + settings_file = self.settings.named_conf + template_file = "/etc/cobbler/named.template" + forward_zones = self.settings.manage_forward_zones + reverse_zones = self.settings.manage_reverse_zones + + metadata = {'zone_include': ''} + for zone in self.__config_forward_zones().keys(): + txt = """ +zone "%(zone)s." { + type master; + file "%(zone)s"; +}; +""" % {'zone': zone} + metadata['zone_include'] = metadata['zone_include'] + txt + + for zone in self.__config_reverse_zones().keys(): + tokens = zone.split('.') + tokens.reverse() + arpa = '.'.join(tokens) + '.in-addr.arpa' + txt = """ +zone "%(arpa)s." { + type master; + file "%(zone)s"; +}; +""" % {'arpa': arpa, 'zone': zone} + metadata['zone_include'] = metadata['zone_include'] + txt + + try: + f2 = open(template_file,"r") + except: + raise CX(_("error reading template from file: %s") % template_file) + template_data = "" + template_data = f2.read() + f2.close() + + self.templar.render(template_data, metadata, settings_file, None) + + def __write_zone_files(self): + """ + Write out the forward and reverse zone files for all the zones + defined in manage_forward_zones and manage_reverse_zones + """ + template_file = "/etc/cobbler/zone.template" + cobbler_server = self.settings.server + serial = int(time.time()) + forward = self.__config_forward_zones() + reverse = self.__config_reverse_zones() + + try: + f2 = open(template_file,"r") + except: + raise CX(_("error reading template from file: %s") % template_file) + template_data = "" + template_data = f2.read() + f2.close() + + for (zone, hosts) in forward.iteritems(): + metadata = { + 'cobbler_server': cobbler_server, + 'serial': serial, + 'host_record': '' + } + + for host in hosts: + txt = '%s\tIN\tA\t%s\n' % host + metadata['host_record'] = metadata['host_record'] + txt + + self.templar.render(template_data, metadata, '/var/named/' + zone, None) + + for (zone, hosts) in reverse.iteritems(): + metadata = { + 'cobbler_server': cobbler_server, + 'serial': serial, + 'host_record': '' + } + + for host in hosts: + txt = '%s\tIN\tPTR\t%s\n' % host + metadata['host_record'] = metadata['host_record'] + txt + + self.templar.render(template_data, metadata, '/var/named/' + zone, None) + + + def write_dns_files(self): + """ + BIND files are written when manage_dns is set in + /var/lib/cobbler/settings. + """ + + self.__write_named_conf() + self.__write_zone_files() + +def get_manager(config): + return IscAndBindManager(config) + |