summaryrefslogtreecommitdiffstats
path: root/cobbler
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2008-05-02 16:05:32 -0400
committerMichael DeHaan <mdehaan@redhat.com>2008-05-02 16:05:32 -0400
commita6fd395b51a624e4aa7d09b4960382784cefa8e8 (patch)
tree6fdab90d58f4d673f1e5e58201a032cd9eb7386b /cobbler
parente4fce2b7321c880f8c1f1adbdf137fc4d66563de (diff)
downloadthird_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.py8
-rw-r--r--cobbler/action_litesync.py24
-rw-r--r--cobbler/action_sync.py18
-rw-r--r--cobbler/api.py17
-rw-r--r--cobbler/dhcpgen.py282
-rw-r--r--cobbler/manage_ctrl.py76
-rw-r--r--cobbler/modules/manage_dnsmasq.py191
-rw-r--r--cobbler/modules/manage_isc_and_bind.py425
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)
+